Repository: prebid/prebid-server
Pull request #2648 (2023-03-16 10:49:48)

AppNexus: remove adpodId test cases
These test cases are already covered by json test framework in video and videosupplemental folder. So removing these test cases. 
I also validated the test coverage and results shows that adPodId cases are in green. Attaching screenshot - 

<img width="1662" alt="Screenshot 2023-03-16 at 4 19 09 PM" src="https://user-images.githubusercontent.com/8147531/225594708-e3a0e82a-0703-4fff-938c-099f2e5454c0.png">



Patch:
diff --git a/config/stored_requests.go b/config/stored_requests.go
index 6bd8a44f..9a3ab260 100644
--- a/config/stored_requests.go
+++ b/config/stored_requests.go
@@ -190,12 +190,20 @@ func (cfg *DatabaseConfig) validate(dataType DataType, errs []error) []error {
 // DatabaseConnection has options which put types to the Database Connection string. See:
 // https://godoc.org/github.com/lib/pq#hdr-Connection_String_Parameters
 type DatabaseConnection struct {
-	Driver   string `mapstructure:"driver"`
-	Database string `mapstructure:"dbname"`
-	Host     string `mapstructure:"host"`
-	Port     int    `mapstructure:"port"`
-	Username string `mapstructure:"user"`
-	Password string `mapstructure:"password"`
+	Driver      string `mapstructure:"driver"`
+	Database    string `mapstructure:"dbname"`
+	Host        string `mapstructure:"host"`
+	Port        int    `mapstructure:"port"`
+	Username    string `mapstructure:"user"`
+	Password    string `mapstructure:"password"`
+	QueryString string `mapstructure:"query_string"`
+	TLS         TLS    `mapstructure:"tls"`
+}
+
+type TLS struct {
+	RootCert   string `mapstructure:"root_cert"`
+	ClientCert string `mapstructure:"client_cert"`
+	ClientKey  string `mapstructure:"client_key"`
 }
 
 type DatabaseFetcherQueries struct {
diff --git a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json
index 80ba523b..47537071 100644
--- a/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json
+++ b/endpoints/openrtb2/sample-requests/amp/valid-supplementary/imp-with-stored-resp.json
@@ -2,7 +2,7 @@
   "description": "Amp request where impression makes reference to a valid stored response with a $5.00 bid",
   "query": "tag_id=101",
   "mockAmpStoredResponse": {
-    "6d718149": "[{\"bid\": [{\"id\": \"bid_id\", \"price\": 5.00, \"ext\": {\"prebid\": {\"targeting\": { \"hb_pb\": \"1.20\", \"hb_cat\": \"IAB-20\", \"hb_cache_id\": \"some_id\"}}}}],\"seat\": \"appnexus\"}]"
+    "6d718149": "[{\"bid\": [{\"id\": \"bid_id\", \"price\": 5.00, \"ext\": {\"prebid\": {\"type\":\"video\", \"targeting\": { \"hb_pb\": \"1.20\", \"hb_cat\": \"IAB-20\", \"hb_cache_id\": \"some_id\"}}}}],\"seat\": \"appnexus\"}]"
   },
   "mockBidRequest": {
     "id": "request-with-stored-resp",
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 9438d71f..ea73b5f2 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -1300,6 +1300,20 @@ func listBiddersWithRequests(bidderRequests []BidderRequest) []openrtb_ext.Bidde
 	return liveAdapters
 }
 
+func getPrebidMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
+	if bid.Ext != nil {
+		var bidExt openrtb_ext.ExtBid
+		err := json.Unmarshal(bid.Ext, &bidExt)
+		if err == nil && bidExt.Prebid != nil {
+			return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type))
+		}
+	}
+
+	return "", &errortypes.BadServerResponse{
+		Message: fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID),
+	}
+}
+
 func buildStoredAuctionResponse(storedAuctionResponses map[string]json.RawMessage) (
 	map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid,
 	*openrtb_ext.Fledge,
@@ -1320,7 +1334,31 @@ func buildStoredAuctionResponse(storedAuctionResponses map[string]json.RawMessag
 			//set imp id from request
 			for i := range seat.Bid {
 				seat.Bid[i].ImpID = impId
-				bidsToAdd = append(bidsToAdd, &entities.PbsOrtbBid{Bid: &seat.Bid[i]})
+				mType := seat.Bid[i].MType
+				var bidType openrtb_ext.BidType
+				if mType > 0 {
+					switch mType {
+					case openrtb2.MarkupBanner:
+						bidType = openrtb_ext.BidTypeBanner
+					case openrtb2.MarkupVideo:
+						bidType = openrtb_ext.BidTypeVideo
+					case openrtb2.MarkupAudio:
+						bidType = openrtb_ext.BidTypeAudio
+					case openrtb2.MarkupNative:
+						bidType = openrtb_ext.BidTypeNative
+					default:
+						return nil, nil, nil, &errortypes.BadServerResponse{
+							Message: fmt.Sprintf("Failed to parse bid mType for impression \"%s\"", seat.Bid[i].ImpID),
+						}
+					}
+				} else {
+					var err error
+					bidType, err = getPrebidMediaTypeForBid(seat.Bid[i])
+					if err != nil {
+						return nil, nil, nil, err
+					}
+				}
+				bidsToAdd = append(bidsToAdd, &entities.PbsOrtbBid{Bid: &seat.Bid[i], BidType: bidType})
 			}
 
 			bidderName := openrtb_ext.BidderName(seat.Seat)
diff --git a/static/bidder-info/impactify.yaml b/static/bidder-info/impactify.yaml
index ec2cb727..ac0d0c3a 100644
--- a/static/bidder-info/impactify.yaml
+++ b/static/bidder-info/impactify.yaml
@@ -1,6 +1,6 @@
 endpoint: "https://sonic.impactify.media/bidder"
 maintainer:
-  email: "support@impactify.io"
+  email: "contact@impactify.io"
 gvlVendorID: 606
 capabilities:
   site:
@@ -11,4 +11,3 @@ userSync:
   iframe:
     url: "https://sonic.impactify.media/static/cookie_sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect_url={{.RedirectURL}}"
     userMacro: "{IMPACTIFY_UID}"
-
diff --git a/stored_requests/backends/db_provider/db_provider.go b/stored_requests/backends/db_provider/db_provider.go
index df6ae81e..0f79a773 100644
--- a/stored_requests/backends/db_provider/db_provider.go
+++ b/stored_requests/backends/db_provider/db_provider.go
@@ -10,7 +10,7 @@ import (
 
 type DbProvider interface {
 	Config() config.DatabaseConnection
-	ConnString() string
+	ConnString() (string, error)
 	Open() error
 	Close() error
 	Ping() error
diff --git a/stored_requests/backends/db_provider/db_provider_mock.go b/stored_requests/backends/db_provider/db_provider_mock.go
index 3432f62e..3d4cfda7 100644
--- a/stored_requests/backends/db_provider/db_provider_mock.go
+++ b/stored_requests/backends/db_provider/db_provider_mock.go
@@ -32,8 +32,8 @@ func (provider DbProviderMock) Config() config.DatabaseConnection {
 	return config.DatabaseConnection{}
 }
 
-func (provider DbProviderMock) ConnString() string {
-	return ""
+func (provider DbProviderMock) ConnString() (string, error) {
+	return "", nil
 }
 
 func (provider DbProviderMock) Open() error {
diff --git a/stored_requests/backends/db_provider/mysql_dbprovider.go b/stored_requests/backends/db_provider/mysql_dbprovider.go
index 91c37f04..9e1b2e3e 100644
--- a/stored_requests/backends/db_provider/mysql_dbprovider.go
+++ b/stored_requests/backends/db_provider/mysql_dbprovider.go
@@ -3,15 +3,23 @@ package db_provider
 import (
 	"bytes"
 	"context"
+	"crypto/tls"
+	"crypto/x509"
 	"database/sql"
+	"errors"
+	"fmt"
+	"io/ioutil"
 	"regexp"
 	"sort"
 	"strconv"
 	"strings"
 
+	"github.com/go-sql-driver/mysql"
 	"github.com/prebid/prebid-server/config"
 )
 
+const customTLSKey = "prebid-tls"
+
 type MySqlDbProvider struct {
 	cfg config.DatabaseConnection
 	db  *sql.DB
@@ -22,8 +30,12 @@ func (provider *MySqlDbProvider) Config() config.DatabaseConnection {
 }
 
 func (provider *MySqlDbProvider) Open() error {
-	db, err := sql.Open(provider.cfg.Driver, provider.ConnString())
+	connStr, err := provider.ConnString()
+	if err != nil {
+		return err
+	}
 
+	db, err := sql.Open(provider.cfg.Driver, connStr)
 	if err != nil {
 		return err
 	}
@@ -46,7 +58,7 @@ func (provider *MySqlDbProvider) Ping() error {
 	return provider.db.Ping()
 }
 
-func (provider *MySqlDbProvider) ConnString() string {
+func (provider *MySqlDbProvider) ConnString() (string, error) {
 	buffer := bytes.NewBuffer(nil)
 
 	if provider.cfg.Username != "" {
@@ -75,7 +87,105 @@ func (provider *MySqlDbProvider) ConnString() string {
 		buffer.WriteString(provider.cfg.Database)
 	}
 
-	return buffer.String()
+	queryStr := provider.generateQueryString()
+
+	if provider.cfg.TLS.RootCert != "" {
+		if err := setupTLSConfig(provider); err != nil {
+			return "", err
+		}
+	}
+
+	if queryStr != "" {
+		buffer.WriteString("?")
+		buffer.WriteString(queryStr)
+	}
+
+	return buffer.String(), nil
+}
+
+func setupTLSConfig(provider *MySqlDbProvider) error {
+	rootCertPool := x509.NewCertPool()
+
+	pem, err := ioutil.ReadFile(provider.cfg.TLS.RootCert)
+	if err != nil {
+		return err
+	}
+
+	if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
+		return fmt.Errorf("failed to parse certificate: %s", provider.cfg.TLS.RootCert)
+	}
+
+	var clientCert []tls.Certificate
+	if provider.cfg.TLS.ClientCert != "" && provider.cfg.TLS.ClientKey != "" {
+		clientCert = make([]tls.Certificate, 0, 1)
+		certs, err := tls.LoadX509KeyPair(provider.cfg.TLS.ClientCert, provider.cfg.TLS.ClientKey)
+		if err != nil {
+			return err
+		}
+
+		clientCert = append(clientCert, certs)
+	}
+
+	mysql.RegisterTLSConfig(provider.getTLSKey(), &tls.Config{
+		RootCAs:               rootCertPool,
+		Certificates:          clientCert,
+		InsecureSkipVerify:    true,
+		VerifyPeerCertificate: verifyPeerCertFunc(rootCertPool),
+	})
+
+	return nil
+}
+
+// verifyPeerCertFunc returns a function that verifies the peer certificate is
+// in the cert pool.
+func verifyPeerCertFunc(pool *x509.CertPool) func([][]byte, [][]*x509.Certificate) error {
+	return func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
+		if len(rawCerts) == 0 {
+			return errors.New("no certificates available to verify")
+		}
+
+		cert, err := x509.ParseCertificate(rawCerts[0])
+		if err != nil {
+			return err
+		}
+
+		opts := x509.VerifyOptions{Roots: pool}
+		if _, err = cert.Verify(opts); err != nil {
+			return err
+		}
+		return nil
+	}
+}
+
+func (provider *MySqlDbProvider) generateQueryString() string {
+	tls := ""
+
+	if provider.cfg.TLS.RootCert != "" {
+		tls = provider.getTLSKey()
+	}
+
+	if tls != "" {
+		if len(provider.cfg.QueryString) == 0 {
+			return "tls=" + tls
+		}
+		if !strings.Contains(provider.cfg.QueryString, "tls=") {
+			return "tls=" + tls + "&" + provider.cfg.QueryString
+		}
+	}
+
+	return provider.cfg.QueryString
+}
+
+func (provider *MySqlDbProvider) getTLSKey() string {
+	pairs := strings.Split(provider.cfg.QueryString, "&")
+
+	for _, pair := range pairs {
+		if strings.HasPrefix(pair, "tls=") {
+			return strings.Split(pair, "=")[1]
+		}
+	}
+
+	return customTLSKey
 }
 
 func (provider *MySqlDbProvider) PrepareQuery(template string, params ...QueryParam) (query string, args []interface{}) {
diff --git a/stored_requests/backends/db_provider/postgres_dbprovider.go b/stored_requests/backends/db_provider/postgres_dbprovider.go
index cbd8d9d0..ef945fae 100644
--- a/stored_requests/backends/db_provider/postgres_dbprovider.go
+++ b/stored_requests/backends/db_provider/postgres_dbprovider.go
@@ -4,7 +4,9 @@ import (
 	"bytes"
 	"context"
 	"database/sql"
+	"errors"
 	"fmt"
+	"net/url"
 	"strconv"
 	"strings"
 
@@ -21,8 +23,12 @@ func (provider *PostgresDbProvider) Config() config.DatabaseConnection {
 }
 
 func (provider *PostgresDbProvider) Open() error {
-	db, err := sql.Open(provider.cfg.Driver, provider.ConnString())
+	connStr, err := provider.ConnString()
+	if err != nil {
+		return err
+	}
 
+	db, err := sql.Open(provider.cfg.Driver, connStr)
 	if err != nil {
 		return err
 	}
@@ -45,41 +51,87 @@ func (provider *PostgresDbProvider) Ping() error {
 	return provider.db.Ping()
 }
 
-func (provider *PostgresDbProvider) ConnString() string {
+func (provider *PostgresDbProvider) ConnString() (string, error) {
 	buffer := bytes.NewBuffer(nil)
+	buffer.WriteString("postgresql://")
+
+	if provider.cfg.Username != "" {
+		buffer.WriteString(provider.cfg.Username)
+		if provider.cfg.Password != "" {
+			buffer.WriteString(":")
+			buffer.WriteString(url.QueryEscape(provider.cfg.Password))
+		}
+		buffer.WriteString("@")
+	}
 
 	if provider.cfg.Host != "" {
-		buffer.WriteString("host=")
 		buffer.WriteString(provider.cfg.Host)
-		buffer.WriteString(" ")
 	}
 
 	if provider.cfg.Port > 0 {
-		buffer.WriteString("port=")
+		buffer.WriteString(":")
 		buffer.WriteString(strconv.Itoa(provider.cfg.Port))
-		buffer.WriteString(" ")
 	}
 
-	if provider.cfg.Username != "" {
-		buffer.WriteString("user=")
-		buffer.WriteString(provider.cfg.Username)
-		buffer.WriteString(" ")
+	if provider.cfg.Database != "" {
+		buffer.WriteString("/")
+		buffer.WriteString(provider.cfg.Database)
 	}
 
-	if provider.cfg.Password != "" {
-		buffer.WriteString("password=")
-		buffer.WriteString(provider.cfg.Password)
-		buffer.WriteString(" ")
+	queryStr, err := provider.generateQueryString()
+	if err != nil {
+		return "", err
 	}
 
-	if provider.cfg.Database != "" {
-		buffer.WriteString("dbname=")
-		buffer.WriteString(provider.cfg.Database)
-		buffer.WriteString(" ")
+	if queryStr != "" {
+		buffer.WriteString("?")
+		buffer.WriteString(queryStr)
+	}
+
+	return buffer.String(), nil
+}
+
+func (provider *PostgresDbProvider) generateQueryString() (string, error) {
+	isTlsInConfigStruct := provider.cfg.TLS.RootCert != "" ||
+		provider.cfg.TLS.ClientCert != "" ||
+		provider.cfg.TLS.ClientKey != ""
+
+	isTlsInQueryString := strings.Contains(provider.cfg.QueryString, "sslrootcert=") ||
+		strings.Contains(provider.cfg.QueryString, "sslcert=") ||
+		strings.Contains(provider.cfg.QueryString, "sslkey=")
+
+	if isTlsInConfigStruct && isTlsInQueryString {
+		return "", errors.New("TLS cert information must either be specified in the TLS object or the query string but not both.")
+	}
+
+	sslmode := "disable"
+	sslrootcert := ""
+	sslcert := ""
+	sslkey := ""
+	queryString := ""
+
+	if provider.cfg.TLS.RootCert != "" {
+		sslmode = "verify-ca"
+		sslrootcert = fmt.Sprintf("&sslrootcert=%s", provider.cfg.TLS.RootCert)
+
+		if provider.cfg.TLS.ClientCert != "" && provider.cfg.TLS.ClientKey != "" {
+			sslmode = "verify-full"
+			sslcert = fmt.Sprintf("&sslcert=%s", provider.cfg.TLS.ClientCert)
+			sslkey = fmt.Sprintf("&sslkey=%s", provider.cfg.TLS.ClientKey)
+		}
+	}
+	sslmode = fmt.Sprintf("&sslmode=%s", sslmode)
+
+	if len(provider.cfg.QueryString) != 0 {
+		queryString = fmt.Sprintf("&%s", provider.cfg.QueryString)
+
+		if strings.Contains(provider.cfg.QueryString, "sslmode=") {
+			sslmode = ""
+		}
 	}
 
-	buffer.WriteString("sslmode=disable")
-	return buffer.String()
+	params := strings.Join([]string{sslmode, sslrootcert, sslcert, sslkey, queryString}, "")
+	return params[1:], nil
 }
 
 func (provider *PostgresDbProvider) PrepareQuery(template string, params ...QueryParam) (query string, args []interface{}) {


Test patch:
diff --git a/adapters/appnexus/appnexus_test.go b/adapters/appnexus/appnexus_test.go
index e6933ed2..000d07e9 100644
--- a/adapters/appnexus/appnexus_test.go
+++ b/adapters/appnexus/appnexus_test.go
@@ -1,17 +1,11 @@
 package appnexus
 
 import (
-	"encoding/json"
-	"regexp"
 	"testing"
 
-	"github.com/prebid/prebid-server/adapters"
 	"github.com/prebid/prebid-server/adapters/adapterstest"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
-
-	"github.com/prebid/openrtb/v17/openrtb2"
-	"github.com/stretchr/testify/assert"
 )
 
 func TestJsonSamples(t *testing.T) {
@@ -32,228 +26,3 @@ func TestMemberQueryParam(t *testing.T) {
 		t.Errorf("appendMemberId() failed on URI with query string. Expected %s, got %s", expected, uriWithMember)
 	}
 }
-
-func TestVideoSinglePod(t *testing.T) {
-	var a adapter
-	a.URI = "http://test.com/openrtb2"
-	a.hbSource = 5
-
-	var reqInfo adapters.ExtraRequestInfo
-	reqInfo.PbsEntryPoint = "video"
-
-	var req openrtb2.BidRequest
-	req.ID = "test_id"
-
-	reqExt := `{"prebid":{}}`
-	impExt := `{"bidder":{"placementId":123, "generate_ad_pod_id":true}}`
-	req.Ext = []byte(reqExt)
-
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_0", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_1", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_2", Ext: []byte(impExt)})
-
-	result, err := a.MakeRequests(&req, &reqInfo)
-
-	assert.Empty(t, err, "Errors array should be empty")
-	assert.Len(t, result, 1, "Only one request should be returned")
-
-	var error error
-	var reqData *openrtb2.BidRequest
-	error = json.Unmarshal(result[0].Body, &reqData)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt *appnexusReqExt
-	error = json.Unmarshal(reqData.Ext, &reqDataExt)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	regMatch, matchErr := regexp.Match(`^[0-9]+$`, []byte(reqDataExt.Appnexus.AdPodId))
-	assert.NoError(t, matchErr, "Regex match error should be nil")
-	assert.True(t, regMatch, "AdPod id doesn't present in Appnexus extension or has incorrect format")
-}
-
-func TestVideoSinglePodManyImps(t *testing.T) {
-	var a adapter
-	a.URI = "http://test.com/openrtb2"
-	a.hbSource = 5
-
-	var reqInfo adapters.ExtraRequestInfo
-	reqInfo.PbsEntryPoint = "video"
-
-	var req openrtb2.BidRequest
-	req.ID = "test_id"
-
-	reqExt := `{"prebid":{}}`
-	impExt := `{"bidder":{"placementId":123}}`
-	req.Ext = []byte(reqExt)
-
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_0", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_1", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_2", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_3", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_4", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_5", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_6", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_7", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_8", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_9", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_10", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_11", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_12", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_13", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_14", Ext: []byte(impExt)})
-
-	res, err := a.MakeRequests(&req, &reqInfo)
-
-	assert.Empty(t, err, "Errors array should be empty")
-	assert.Len(t, res, 2, "Two requests should be returned")
-
-	var error error
-	var reqData1 *openrtb2.BidRequest
-	error = json.Unmarshal(res[0].Body, &reqData1)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt1 *appnexusReqExt
-	error = json.Unmarshal(reqData1.Ext, &reqDataExt1)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	assert.Equal(t, "", reqDataExt1.Appnexus.AdPodId, "AdPod id should not be present in first request")
-
-	var reqData2 *openrtb2.BidRequest
-	error = json.Unmarshal(res[1].Body, &reqData2)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt2 *appnexusReqExt
-	error = json.Unmarshal(reqData2.Ext, &reqDataExt2)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	assert.Equal(t, "", reqDataExt2.Appnexus.AdPodId, "AdPod id should not be present in second request")
-}
-
-func TestVideoTwoPods(t *testing.T) {
-	var a adapter
-	a.URI = "http://test.com/openrtb2"
-	a.hbSource = 5
-
-	var reqInfo adapters.ExtraRequestInfo
-	reqInfo.PbsEntryPoint = "video"
-
-	var req openrtb2.BidRequest
-	req.ID = "test_id"
-
-	reqExt := `{"prebid":{}}`
-	impExt := `{"bidder":{"placementId":123, "generate_ad_pod_id": true}}`
-	req.Ext = []byte(reqExt)
-
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_0", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_1", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_2", Ext: []byte(impExt)})
-
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_0", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_1", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_2", Ext: []byte(impExt)})
-
-	res, err := a.MakeRequests(&req, &reqInfo)
-
-	assert.Empty(t, err, "Errors array should be empty")
-	assert.Len(t, res, 2, "Two request should be returned")
-
-	var error error
-	var reqData1 *openrtb2.BidRequest
-	error = json.Unmarshal(res[0].Body, &reqData1)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt1 *appnexusReqExt
-	error = json.Unmarshal(reqData1.Ext, &reqDataExt1)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	adPodId1 := reqDataExt1.Appnexus.AdPodId
-
-	var reqData2 *openrtb2.BidRequest
-	error = json.Unmarshal(res[1].Body, &reqData2)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt2 *appnexusReqExt
-	error = json.Unmarshal(reqData2.Ext, &reqDataExt2)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	adPodId2 := reqDataExt2.Appnexus.AdPodId
-
-	assert.NotEqual(t, adPodId1, adPodId2, "AdPod id should be different for different pods")
-}
-
-func TestVideoTwoPodsManyImps(t *testing.T) {
-	var a adapter
-	a.URI = "http://test.com/openrtb2"
-	a.hbSource = 5
-
-	var reqInfo adapters.ExtraRequestInfo
-	reqInfo.PbsEntryPoint = "video"
-
-	var req openrtb2.BidRequest
-	req.ID = "test_id"
-
-	reqExt := `{"prebid":{}}`
-	impExt := `{"bidder":{"placementId":123, "generate_ad_pod_id":true}}`
-	req.Ext = []byte(reqExt)
-
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_0", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_1", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "1_2", Ext: []byte(impExt)})
-
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_0", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_1", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_2", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_3", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_4", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_5", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_6", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_7", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_8", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_9", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_10", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_11", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_12", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_13", Ext: []byte(impExt)})
-	req.Imp = append(req.Imp, openrtb2.Imp{ID: "2_14", Ext: []byte(impExt)})
-
-	res, err := a.MakeRequests(&req, &reqInfo)
-
-	assert.Empty(t, err, "Errors array should be empty")
-	assert.Len(t, res, 3, "Three requests should be returned")
-
-	var error error
-	var reqData1 *openrtb2.BidRequest
-	error = json.Unmarshal(res[0].Body, &reqData1)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt1 *appnexusReqExt
-	error = json.Unmarshal(reqData1.Ext, &reqDataExt1)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	var reqData2 *openrtb2.BidRequest
-	error = json.Unmarshal(res[1].Body, &reqData2)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt2 *appnexusReqExt
-	error = json.Unmarshal(reqData2.Ext, &reqDataExt2)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	var reqData3 *openrtb2.BidRequest
-	error = json.Unmarshal(res[2].Body, &reqData3)
-	assert.NoError(t, error, "Response body unmarshalling error should be nil")
-
-	var reqDataExt3 *appnexusReqExt
-	error = json.Unmarshal(reqData3.Ext, &reqDataExt3)
-	assert.NoError(t, error, "Response ext unmarshalling error should be nil")
-
-	adPodId1 := reqDataExt1.Appnexus.AdPodId
-	adPodId2 := reqDataExt2.Appnexus.AdPodId
-	adPodId3 := reqDataExt3.Appnexus.AdPodId
-
-	podIds := make(map[string]int)
-	podIds[adPodId1] = podIds[adPodId1] + 1
-	podIds[adPodId2] = podIds[adPodId2] + 1
-	podIds[adPodId3] = podIds[adPodId3] + 1
-
-	assert.Len(t, podIds, 2, "Incorrect number of unique pod ids")
-}
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 44aa3cc6..500e6751 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -4117,7 +4117,7 @@ func TestStoredAuctionResponses(t *testing.T) {
 		SeatBid: []openrtb2.SeatBid{
 			{
 				Bid: []openrtb2.Bid{
-					{ID: "bid_id", ImpID: "impression-id", Ext: json.RawMessage(`{"origbidcpm":0,"prebid":{"type":""}}`)},
+					{ID: "bid_id", ImpID: "impression-id", Ext: json.RawMessage(`{"origbidcpm":0,"prebid":{"type":"video"}}`)},
 				},
 				Seat: "appnexus",
 			},
@@ -4132,7 +4132,7 @@ func TestStoredAuctionResponses(t *testing.T) {
 		{
 			desc: "Single imp with valid stored response",
 			storedAuctionResp: map[string]json.RawMessage{
-				"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id"}],"seat": "appnexus"}]`),
+				"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"type": "video"}}}],"seat": "appnexus"}]`),
 			},
 			errorExpected: false,
 		},
@@ -4179,15 +4179,16 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 	}
 
 	testCases := []struct {
-		desc     string
-		in       testIn
-		expected testResults
+		desc         string
+		in           testIn
+		expected     testResults
+		errorMessage string
 	}{
 		{
 			desc: "Single imp with single stored response bid",
 			in: testIn{
 				StoredAuctionResponses: map[string]json.RawMessage{
-					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id"}],"seat": "appnexus"}]`),
+					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
 				},
 			},
 			expected: testResults{
@@ -4195,7 +4196,8 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 					openrtb_ext.BidderName("appnexus"): {
 						Bids: []*entities.PbsOrtbBid{
 							{
-								Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id"},
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeNative,
 							},
 						},
 					},
@@ -4203,19 +4205,41 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 				liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
 			},
 		},
+		{
+			desc: "Single imp with single stored response bid with incorrect bid type",
+			in: testIn{
+				StoredAuctionResponses: map[string]json.RawMessage{
+					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"type": "incorrect"}}}],"seat": "appnexus"}]`),
+				},
+			},
+			expected: testResults{
+				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
+					openrtb_ext.BidderName("appnexus"): {
+						Bids: []*entities.PbsOrtbBid{
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeNative,
+							},
+						},
+					},
+				},
+				liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
+			},
+			errorMessage: "invalid BidType: incorrect",
+		},
 		{
 			desc: "Single imp with multiple bids in stored response one bidder",
 			in: testIn{
 				StoredAuctionResponses: map[string]json.RawMessage{
-					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id1"}, {"id": "bid_id2"}],"seat": "appnexus"}]`),
+					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "bid_id2", "ext": {"prebid": {"type": "video"}}}],"seat": "appnexus"}]`),
 				},
 			},
 			expected: testResults{
 				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
 					openrtb_ext.BidderName("appnexus"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "bid_id1", ImpID: "impression-id"}},
-							{Bid: &openrtb2.Bid{ID: "bid_id2", ImpID: "impression-id"}},
+							{Bid: &openrtb2.Bid{ID: "bid_id1", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "bid_id2", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "video"}}`)}, BidType: openrtb_ext.BidTypeVideo},
 						},
 					},
 				},
@@ -4226,21 +4250,21 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 			desc: "Single imp with multiple bids in stored response two bidders",
 			in: testIn{
 				StoredAuctionResponses: map[string]json.RawMessage{
-					"impression-id": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
+					"impression-id": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "banner"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "banner"}}}],"seat": "rubicon"}]`),
 				},
 			},
 			expected: testResults{
 				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
 					openrtb_ext.BidderName("appnexus"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id"}},
+							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
 						},
 					},
 					openrtb_ext.BidderName("rubicon"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id"}},
-							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id"}},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "banner"}}`)}, BidType: openrtb_ext.BidTypeBanner},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "banner"}}`)}, BidType: openrtb_ext.BidTypeBanner},
 						},
 					},
 				},
@@ -4251,24 +4275,24 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 			desc: "Two imps with two bids in stored response two bidders, different bids number",
 			in: testIn{
 				StoredAuctionResponses: map[string]json.RawMessage{
-					"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}]`),
-					"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
+					"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+					"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "rubicon"}]`),
 				},
 			},
 			expected: testResults{
 				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
 					openrtb_ext.BidderName("appnexus"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2"}},
+							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
 						},
 					},
 					openrtb_ext.BidderName("rubicon"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2"}},
-							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2"}},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
 						},
 					},
 				},
@@ -4279,26 +4303,26 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 			desc: "Two imps with two bids in stored response two bidders",
 			in: testIn{
 				StoredAuctionResponses: map[string]json.RawMessage{
-					"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
-					"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
+					"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "rubicon"}]`),
+					"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "rubicon"}]`),
 				},
 			},
 			expected: testResults{
 				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
 					openrtb_ext.BidderName("appnexus"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2"}},
-							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2"}},
+							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
 						},
 					},
 					openrtb_ext.BidderName("rubicon"): {
 						Bids: []*entities.PbsOrtbBid{
-							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id1"}},
-							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id1"}},
-							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2"}},
-							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2"}},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
+							{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
 						},
 					},
 				},
@@ -4331,19 +4355,101 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
 				},
 			},
 		},
+		{
+			desc: "Single imp with single stored response bid with bid.mtype",
+			in: testIn{
+				StoredAuctionResponses: map[string]json.RawMessage{
+					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 2, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+				},
+			},
+			expected: testResults{
+				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
+					openrtb_ext.BidderName("appnexus"): {
+						Bids: []*entities.PbsOrtbBid{
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", MType: 2, Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeVideo,
+							},
+						},
+					},
+				},
+				liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
+			},
+		},
+		{
+			desc: "Multiple imps with multiple stored response bid with bid.mtype and different types",
+			in: testIn{
+				StoredAuctionResponses: map[string]json.RawMessage{
+					"impression-id1": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 1, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+					"impression-id2": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 2, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+					"impression-id3": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 3, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+					"impression-id4": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 4, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+				},
+			},
+			expected: testResults{
+				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
+					openrtb_ext.BidderName("appnexus"): {
+						Bids: []*entities.PbsOrtbBid{
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id1", MType: 1, Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeBanner,
+							},
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id2", MType: 2, Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeVideo,
+							},
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id3", MType: 3, Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeAudio,
+							},
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id4", MType: 4, Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeNative,
+							},
+						},
+					},
+				},
+				liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
+			},
+		},
+		{
+			desc: "Single imp with single stored response bid with incorrect bid.mtype",
+			in: testIn{
+				StoredAuctionResponses: map[string]json.RawMessage{
+					"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 10, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
+				},
+			},
+			expected: testResults{
+				adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
+					openrtb_ext.BidderName("appnexus"): {
+						Bids: []*entities.PbsOrtbBid{
+							{
+								Bid:     &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", MType: 2, Ext: []byte(`{"prebid": {"type": "native"}}`)},
+								BidType: openrtb_ext.BidTypeVideo,
+							},
+						},
+					},
+				},
+				liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
+			},
+			errorMessage: "Failed to parse bid mType for impression \"impression-id\"",
+		},
 	}
 	for _, test := range testCases {
 
 		bids, fledge, adapters, err := buildStoredAuctionResponse(test.in.StoredAuctionResponses)
-		assert.NoErrorf(t, err, "%s. HoldAuction error: %v \n", test.desc, err)
+		if len(test.errorMessage) > 0 {
+			assert.Equal(t, test.errorMessage, err.Error(), " incorrect expected error")
+		} else {
+			assert.NoErrorf(t, err, "%s. HoldAuction error: %v \n", test.desc, err)
 
-		assert.ElementsMatch(t, test.expected.liveAdapters, adapters, "Incorrect adapter list")
-		assert.Equal(t, fledge, test.expected.fledge, "Incorrect FLEDGE response")
+			assert.ElementsMatch(t, test.expected.liveAdapters, adapters, "Incorrect adapter list")
+			assert.Equal(t, fledge, test.expected.fledge, "Incorrect FLEDGE response")
 
-		for _, bidderName := range test.expected.liveAdapters {
-			assert.ElementsMatch(t, test.expected.adapterBids[bidderName].Bids, bids[bidderName].Bids, "Incorrect bids")
+			for _, bidderName := range test.expected.liveAdapters {
+				assert.ElementsMatch(t, test.expected.adapterBids[bidderName].Bids, bids[bidderName].Bids, "Incorrect bids")
+			}
 		}
-
 	}
 }
 
diff --git a/stored_requests/backends/db_provider/mysql_dbprovider_test.go b/stored_requests/backends/db_provider/mysql_dbprovider_test.go
index e0796d00..e47280ef 100644
--- a/stored_requests/backends/db_provider/mysql_dbprovider_test.go
+++ b/stored_requests/backends/db_provider/mysql_dbprovider_test.go
@@ -1,6 +1,9 @@
 package db_provider
 
 import (
+	"fmt"
+	"path"
+	"runtime"
 	"testing"
 
 	"github.com/prebid/prebid-server/config"
@@ -8,14 +11,26 @@ import (
 )
 
 func TestConnStringMySql(t *testing.T) {
+
+	type TLS struct {
+		RootCert   string
+		ClientCert string
+		ClientKey  string
+	}
+
 	type Params struct {
-		db       string
-		host     string
-		port     int
-		username string
-		password string
+		db          string
+		host        string
+		port        int
+		username    string
+		password    string
+		QueryString string
+		TLS         TLS
 	}
 
+	_, callerFilename, _, _ := runtime.Caller(0)
+	workingDir := path.Dir(callerFilename)
+
 	tests := []struct {
 		name       string
 		params     Params
@@ -58,6 +73,13 @@ func TestConnStringMySql(t *testing.T) {
 			},
 			connString: "someuser:somepassword@tcp()/",
 		},
+		{
+			params: Params{
+				username: "someuser",
+				password: "somepassword:/?#[]@!$&()*+,;=",
+			},
+			connString: "someuser:somepassword:/?#[]@!$&()*+,;=@tcp()/",
+		},
 		{
 			params: Params{
 				db:       "TestDB",
@@ -68,22 +90,152 @@ func TestConnStringMySql(t *testing.T) {
 			},
 			connString: "someuser:somepassword@tcp(example.com:20)/TestDB",
 		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value",
+			},
+			connString: "someuser:somepassword@tcp(example.com:20)/TestDB?param=value",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value&tls=preferred",
+			},
+			connString: "someuser:somepassword@tcp(example.com:20)/TestDB?param=value&tls=preferred",
+		},
+		{
+			params: Params{
+				db:       "TestDB",
+				host:     "example.com",
+				port:     20,
+				username: "someuser",
+				password: "somepassword",
+				TLS: TLS{
+					RootCert: path.Join(workingDir, "test_assets/root-cert.pem"),
+				},
+			},
+			connString: fmt.Sprintf("someuser:somepassword@tcp(example.com:20)/TestDB?tls=%s", customTLSKey),
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "tls=tlsKeyByQueryString",
+				TLS: TLS{
+					RootCert: path.Join(workingDir, "test_assets/root-cert.pem"),
+				},
+			},
+			connString: "someuser:somepassword@tcp(example.com:20)/TestDB?tls=tlsKeyByQueryString",
+		},
+		{
+			params: Params{
+				db:       "TestDB",
+				host:     "example.com",
+				port:     20,
+				username: "someuser",
+				password: "somepassword",
+				TLS: TLS{
+					RootCert:   path.Join(workingDir, "test_assets/root-cert.pem"),
+					ClientCert: path.Join(workingDir, "test_assets/client-cert.pem"),
+					ClientKey:  path.Join(workingDir, "test_assets/client-key.pem"),
+				},
+			},
+			connString: fmt.Sprintf("someuser:somepassword@tcp(example.com:20)/TestDB?tls=%s", customTLSKey),
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value",
+				TLS: TLS{
+					RootCert:   path.Join(workingDir, "test_assets/root-cert.pem"),
+					ClientCert: path.Join(workingDir, "test_assets/client-cert.pem"),
+					ClientKey:  path.Join(workingDir, "test_assets/client-key.pem"),
+				},
+			},
+			connString: fmt.Sprintf("someuser:somepassword@tcp(example.com:20)/TestDB?tls=%s&param=value", customTLSKey),
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "tls=preferred",
+				TLS: TLS{
+					RootCert:   path.Join(workingDir, "test_assets/root-cert.pem"),
+					ClientCert: path.Join(workingDir, "test_assets/client-cert.pem"),
+					ClientKey:  path.Join(workingDir, "test_assets/client-key.pem"),
+				},
+			},
+			connString: "someuser:somepassword@tcp(example.com:20)/TestDB?tls=preferred",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value&tls=preferred",
+				TLS: TLS{
+					RootCert:   path.Join(workingDir, "test_assets/root-cert.pem"),
+					ClientCert: path.Join(workingDir, "test_assets/client-cert.pem"),
+					ClientKey:  path.Join(workingDir, "test_assets/client-key.pem"),
+				},
+			},
+			connString: "someuser:somepassword@tcp(example.com:20)/TestDB?param=value&tls=preferred",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value&tls=tlsKeyByQueryString",
+				TLS: TLS{
+					RootCert:   path.Join(workingDir, "test_assets/root-cert.pem"),
+					ClientCert: path.Join(workingDir, "test_assets/client-cert.pem"),
+					ClientKey:  path.Join(workingDir, "test_assets/client-key.pem"),
+				},
+			},
+			connString: "someuser:somepassword@tcp(example.com:20)/TestDB?param=value&tls=tlsKeyByQueryString",
+		},
 	}
 
 	for _, test := range tests {
 		cfg := config.DatabaseConnection{
-			Database: test.params.db,
-			Host:     test.params.host,
-			Port:     test.params.port,
-			Username: test.params.username,
-			Password: test.params.password,
+			Database:    test.params.db,
+			Host:        test.params.host,
+			Port:        test.params.port,
+			Username:    test.params.username,
+			Password:    test.params.password,
+			QueryString: test.params.QueryString,
+			TLS:         config.TLS(test.params.TLS),
 		}
 
 		provider := MySqlDbProvider{
 			cfg: cfg,
 		}
 
-		connString := provider.ConnString()
+		connString, _ := provider.ConnString()
 		assert.Equal(t, test.connString, connString, "Strings did not match")
 	}
 }
diff --git a/stored_requests/backends/db_provider/postgres_dbprovider_test.go b/stored_requests/backends/db_provider/postgres_dbprovider_test.go
index 50d825df..9e98c0b5 100644
--- a/stored_requests/backends/db_provider/postgres_dbprovider_test.go
+++ b/stored_requests/backends/db_provider/postgres_dbprovider_test.go
@@ -1,6 +1,7 @@
 package db_provider
 
 import (
+	"errors"
 	"testing"
 
 	"github.com/prebid/prebid-server/config"
@@ -8,55 +9,72 @@ import (
 )
 
 func TestConnStringPostgres(t *testing.T) {
+
+	type TLS struct {
+		RootCert   string
+		ClientCert string
+		ClientKey  string
+	}
+
 	type Params struct {
-		db       string
-		host     string
-		port     int
-		username string
-		password string
+		db          string
+		host        string
+		port        int
+		username    string
+		password    string
+		QueryString string
+		TLS         TLS
 	}
 
 	tests := []struct {
-		name       string
-		params     Params
-		connString string
+		name          string
+		params        Params
+		connString    string
+		expectedError error
 	}{
 		{
 			params: Params{
 				db: "",
 			},
-			connString: "sslmode=disable",
+			connString: "postgresql://?sslmode=disable",
 		},
 		{
 			params: Params{
 				db: "TestDB",
 			},
-			connString: "dbname=TestDB sslmode=disable",
+			connString: "postgresql:///TestDB?sslmode=disable",
 		},
 		{
 			params: Params{
 				host: "example.com",
 			},
-			connString: "host=example.com sslmode=disable",
+			connString: "postgresql://example.com?sslmode=disable",
 		},
 		{
 			params: Params{
 				port: 20,
 			},
-			connString: "port=20 sslmode=disable",
+			connString: "postgresql://:20?sslmode=disable",
 		},
 		{
 			params: Params{
 				username: "someuser",
 			},
-			connString: "user=someuser sslmode=disable",
+			connString: "postgresql://someuser@?sslmode=disable",
 		},
 		{
 			params: Params{
 				username: "someuser",
 				password: "somepassword",
 			},
-			connString: "user=someuser password=somepassword sslmode=disable",
+			connString: "postgresql://someuser:somepassword@?sslmode=disable",
+		},
+		{
+			params: Params{
+				username: "someuser",
+				password: "somepassword:/?#[]@!$&()*+,;=",
+			},
+			connString: "postgresql://someuser:somepassword%3A%2F%3F%23%5B%5D%40%21%24%26%28%29%2A%2B%2C%3B%3D@?sslmode=disable",
 		},
 		{
 			params: Params{
@@ -66,24 +84,203 @@ func TestConnStringPostgres(t *testing.T) {
 				username: "someuser",
 				password: "somepassword",
 			},
-			connString: "host=example.com port=20 user=someuser password=somepassword dbname=TestDB sslmode=disable",
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslmode=disable",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value",
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslmode=disable&param=value",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value&sslmode=require",
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?param=value&sslmode=require",
+		},
+		{
+			params: Params{
+				db:       "TestDB",
+				host:     "example.com",
+				port:     20,
+				username: "someuser",
+				password: "somepassword",
+				TLS: TLS{
+					RootCert: "root-cert.pem",
+				},
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslmode=verify-ca&sslrootcert=root-cert.pem",
+		},
+		{
+			params: Params{
+				db:       "TestDB",
+				host:     "example.com",
+				port:     20,
+				username: "someuser",
+				password: "somepassword",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslmode=verify-full&sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslmode=verify-full&sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem&param=value",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "sslmode=prefer",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem&sslmode=prefer",
+		},
+		{
+			params: Params{
+				db:          "TestDB",
+				host:        "example.com",
+				port:        20,
+				username:    "someuser",
+				password:    "somepassword",
+				QueryString: "param=value&sslmode=prefer",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString: "postgresql://someuser:somepassword@example.com:20/TestDB?sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem&param=value&sslmode=prefer",
+		},
+		{
+			params: Params{
+				QueryString: "sslrootcert=root-cert.pem",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
+		},
+		{
+			params: Params{
+				QueryString: "sslcert=client-cert.pem",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
+		},
+		{
+			params: Params{
+				QueryString: "sslkey=client-key.pem",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
+		},
+		{
+			params: Params{
+				QueryString: "sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem",
+				TLS: TLS{
+					RootCert: "root-cert.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
+		},
+		{
+			params: Params{
+				QueryString: "sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem",
+				TLS: TLS{
+					ClientCert: "client-cert.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
+		},
+		{
+			params: Params{
+				QueryString: "sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem",
+				TLS: TLS{
+					ClientKey: "client-key.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
+		},
+		{
+			params: Params{
+				QueryString: "sslrootcert=root-cert.pem&sslcert=client-cert.pem&sslkey=client-key.pem",
+				TLS: TLS{
+					RootCert:   "root-cert.pem",
+					ClientCert: "client-cert.pem",
+					ClientKey:  "client-key.pem",
+				},
+			},
+			connString:    "",
+			expectedError: errors.New("TLS cert information must either be specified in the TLS object or the query string but not both."),
 		},
 	}
 
 	for _, test := range tests {
 		cfg := config.DatabaseConnection{
-			Database: test.params.db,
-			Host:     test.params.host,
-			Port:     test.params.port,
-			Username: test.params.username,
-			Password: test.params.password,
+			Database:    test.params.db,
+			Host:        test.params.host,
+			Port:        test.params.port,
+			Username:    test.params.username,
+			Password:    test.params.password,
+			QueryString: test.params.QueryString,
+			TLS:         config.TLS(test.params.TLS),
 		}
 
 		provider := PostgresDbProvider{
 			cfg: cfg,
 		}
 
-		connString := provider.ConnString()
+		connString, err := provider.ConnString()
 		assert.Equal(t, test.connString, connString, "Strings did not match")
+		assert.Equal(t, test.expectedError, err)
 	}
 }