Repository: prebid/prebid-server
Pull request #2645 (2023-03-15 19:54:58)

Emit warnings on conflicts between openrtb 2.6 pre GPP privacy and GPP


Patch:
diff --git a/adapters/adnuntius/adnuntius.go b/adapters/adnuntius/adnuntius.go
index 084ffc22..fe97eaed 100644
--- a/adapters/adnuntius/adnuntius.go
+++ b/adapters/adnuntius/adnuntius.go
@@ -43,6 +43,7 @@ type AdUnit struct {
 			Amount   float64
 			Currency string
 		}
+		DealID          string `json:"dealId,omitempty"`
 		AdId            string
 		CreativeWidth   string
 		CreativeHeight  string
@@ -373,6 +374,7 @@ func generateBidResponse(adnResponse *AdnResponse, request *openrtb2.BidRequest)
 				W:       creativeWidth,
 				H:       creativeHeight,
 				AdID:    ad.AdId,
+				DealID:  ad.DealID,
 				CID:     ad.LineItemId,
 				CrID:    ad.CreativeId,
 				Price:   ad.Bid.Amount * 1000,
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/auction.go b/endpoints/openrtb2/auction.go
index 13b27898..137b66c5 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -18,6 +18,7 @@ import (
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
 	gpplib "github.com/prebid/go-gpp"
+	"github.com/prebid/go-gpp/constants"
 	"github.com/prebid/openrtb/v17/adcom1"
 	"github.com/prebid/openrtb/v17/native1"
 	nativeRequests "github.com/prebid/openrtb/v17/native1/request"
@@ -728,18 +729,6 @@ func (deps *endpointDeps) validateRequest(req *openrtb_ext.RequestWrapper, isAmp
 		return append(errL, err)
 	}
 
-	if err := deps.validateUser(req, aliases); err != nil {
-		return append(errL, err)
-	}
-
-	if err := validateRegs(req); err != nil {
-		return append(errL, err)
-	}
-
-	if err := validateDevice(req.Device); err != nil {
-		return append(errL, err)
-	}
-
 	var gpp gpplib.GppContainer
 	if req.BidRequest.Regs != nil && len(req.BidRequest.Regs.GPP) > 0 {
 		gpp, err = gpplib.Parse(req.BidRequest.Regs.GPP)
@@ -750,8 +739,33 @@ func (deps *endpointDeps) validateRequest(req *openrtb_ext.RequestWrapper, isAmp
 		}
 	}
 
-	if ccpaPolicy, err := ccpa.ReadFromRequestWrapper(req, gpp); err != nil {
+	if errs := deps.validateUser(req, aliases, gpp); errs != nil {
+		if len(errs) > 0 {
+			errL = append(errL, errs...)
+		}
+		if errortypes.ContainsFatalError(errs) {
+			return errL
+		}
+	}
+
+	if errs := validateRegs(req, gpp); errs != nil {
+		if len(errs) > 0 {
+			errL = append(errL, errs...)
+		}
+		if errortypes.ContainsFatalError(errs) {
+			return errL
+		}
+	}
+
+	if err := validateDevice(req.Device); err != nil {
 		return append(errL, err)
+	}
+
+	if ccpaPolicy, err := ccpa.ReadFromRequestWrapper(req, gpp); err != nil {
+		errL = append(errL, err)
+		if errortypes.ContainsFatalError([]error{err}) {
+			return errL
+		}
 	} else if _, err := ccpaPolicy.Parse(exchange.GetValidBidders(aliases)); err != nil {
 		if _, invalidConsent := err.(*errortypes.Warning); invalidConsent {
 			errL = append(errL, &errortypes.Warning{
@@ -1609,29 +1623,41 @@ func (deps *endpointDeps) validateApp(req *openrtb_ext.RequestWrapper) error {
 	return err
 }
 
-func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases map[string]string) error {
+func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases map[string]string, gpp gpplib.GppContainer) []error {
+	var errL []error
+
+	if req == nil || req.BidRequest == nil || req.BidRequest.User == nil {
+		return nil
+	}
 	// The following fields were previously uints in the OpenRTB library we use, but have
 	// since been changed to ints. We decided to maintain the non-negative check.
-	if req != nil && req.BidRequest != nil && req.User != nil {
-		if req.User.Geo != nil && req.User.Geo.Accuracy < 0 {
-			return errors.New("request.user.geo.accuracy must be a positive number")
-		}
+	if req.User.Geo != nil && req.User.Geo.Accuracy < 0 {
+		return append(errL, errors.New("request.user.geo.accuracy must be a positive number"))
 	}
 
+	if req.User.Consent != "" {
+		for _, section := range gpp.Sections {
+			if section.GetID() == constants.SectionTCFEU2 && section.GetValue() != req.User.Consent {
+				errL = append(errL, &errortypes.Warning{
+					Message:     "user.consent GDPR string conflicts with GPP (regs.gpp) GDPR string, using regs.gpp",
+					WarningCode: errortypes.InvalidPrivacyConsentWarningCode})
+			}
+		}
+	}
 	userExt, err := req.GetUserExt()
 	if err != nil {
-		return fmt.Errorf("request.user.ext object is not valid: %v", err)
+		return append(errL, fmt.Errorf("request.user.ext object is not valid: %v", err))
 	}
 	// Check if the buyeruids are valid
 	prebid := userExt.GetPrebid()
 	if prebid != nil {
 		if len(prebid.BuyerUIDs) < 1 {
-			return errors.New(`request.user.ext.prebid requires a "buyeruids" property with at least one ID defined. If none exist, then request.user.ext.prebid should not be defined.`)
+			return append(errL, errors.New(`request.user.ext.prebid requires a "buyeruids" property with at least one ID defined. If none exist, then request.user.ext.prebid should not be defined.`))
 		}
 		for bidderName := range prebid.BuyerUIDs {
 			if _, ok := deps.bidderMap[bidderName]; !ok {
 				if _, ok := aliases[bidderName]; !ok {
-					return fmt.Errorf("request.user.ext.%s is neither a known bidder name nor an alias in request.ext.prebid.aliases.", bidderName)
+					return append(errL, fmt.Errorf("request.user.ext.%s is neither a known bidder name nor an alias in request.ext.prebid.aliases", bidderName))
 				}
 			}
 		}
@@ -1640,45 +1666,64 @@ func (deps *endpointDeps) validateUser(req *openrtb_ext.RequestWrapper, aliases
 	eids := userExt.GetEid()
 	if eids != nil {
 		if len(*eids) == 0 {
-			return errors.New("request.user.ext.eids must contain at least one element or be undefined")
+			return append(errL, errors.New("request.user.ext.eids must contain at least one element or be undefined"))
 		}
 		uniqueSources := make(map[string]struct{}, len(*eids))
 		for eidIndex, eid := range *eids {
 			if eid.Source == "" {
-				return fmt.Errorf("request.user.ext.eids[%d] missing required field: \"source\"", eidIndex)
+				return append(errL, fmt.Errorf("request.user.ext.eids[%d] missing required field: \"source\"", eidIndex))
 			}
 			if _, ok := uniqueSources[eid.Source]; ok {
-				return errors.New("request.user.ext.eids must contain unique sources")
+				return append(errL, errors.New("request.user.ext.eids must contain unique sources"))
 			}
 			uniqueSources[eid.Source] = struct{}{}
 
 			if len(eid.UIDs) == 0 {
-				return fmt.Errorf("request.user.ext.eids[%d].uids must contain at least one element or be undefined", eidIndex)
+				return append(errL, fmt.Errorf("request.user.ext.eids[%d].uids must contain at least one element or be undefined", eidIndex))
 			}
 
 			for uidIndex, uid := range eid.UIDs {
 				if uid.ID == "" {
-					return fmt.Errorf("request.user.ext.eids[%d].uids[%d] missing required field: \"id\"", eidIndex, uidIndex)
+					return append(errL, fmt.Errorf("request.user.ext.eids[%d].uids[%d] missing required field: \"id\"", eidIndex, uidIndex))
 				}
 			}
 		}
 	}
 
-	return nil
+	return errL
 }
 
-func validateRegs(req *openrtb_ext.RequestWrapper) error {
+func validateRegs(req *openrtb_ext.RequestWrapper, gpp gpplib.GppContainer) []error {
+	var errL []error
+
+	if req == nil || req.BidRequest == nil || req.BidRequest.Regs == nil {
+		return nil
+	}
+
+	if req.BidRequest.Regs.GDPR != nil && req.BidRequest.Regs.GPPSID != nil {
+		gdpr := int8(0)
+		for _, id := range req.BidRequest.Regs.GPPSID {
+			if id == int8(constants.SectionTCFEU2) {
+				gdpr = 1
+			}
+		}
+		if gdpr != *req.BidRequest.Regs.GDPR {
+			errL = append(errL, &errortypes.Warning{
+				Message:     "regs.gdpr signal conflicts with GPP (regs.gpp_sid) and will be ignored",
+				WarningCode: errortypes.InvalidPrivacyConsentWarningCode})
+		}
+	}
 	regsExt, err := req.GetRegExt()
 	if err != nil {
-		return fmt.Errorf("request.regs.ext is invalid: %v", err)
+		return append(errL, fmt.Errorf("request.regs.ext is invalid: %v", err))
 	}
 
 	gdpr := regsExt.GetGDPR()
 	if gdpr != nil && *gdpr != 0 && *gdpr != 1 {
-		return errors.New("request.regs.ext.gdpr must be either 0 or 1")
+		return append(errL, errors.New("request.regs.ext.gdpr must be either 0 or 1"))
 	}
 
-	return nil
+	return errL
 }
 
 func validateDevice(device *openrtb2.Device) error {
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/endpoints/openrtb2/sample-requests/invalid-whole/user-ext-prebid-buyeruids-unknown.json b/endpoints/openrtb2/sample-requests/invalid-whole/user-ext-prebid-buyeruids-unknown.json
index 715cc667..83ed675c 100644
--- a/endpoints/openrtb2/sample-requests/invalid-whole/user-ext-prebid-buyeruids-unknown.json
+++ b/endpoints/openrtb2/sample-requests/invalid-whole/user-ext-prebid-buyeruids-unknown.json
@@ -34,5 +34,5 @@
     }
   },
   "expectedReturnCode": 400,
-  "expectedErrorMessage": "Invalid request: request.user.ext.unknown is neither a known bidder name nor an alias in request.ext.prebid.aliases.\n"
+  "expectedErrorMessage": "Invalid request: request.user.ext.unknown is neither a known bidder name nor an alias in request.ext.prebid.aliases\n"
 }
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/gdpr-conflict.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/gdpr-conflict.json
new file mode 100644
index 00000000..3d6a0774
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/gdpr-conflict.json
@@ -0,0 +1,56 @@
+{
+  "description": "Well formed amp request with  conflicting (2.6 gdpr consent vs. GPP) gdpr signals",
+  "mockBidRequest": {
+    "id": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "a3de7af2-a86a-4043-a77b-c7e86744155e"
+      }
+    },
+    "source": {
+      "tid": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5"
+    },
+    "tmax": 1000,
+    "imp": [
+      {
+        "id": "/19968336/header-bid-tag-0",
+        "ext": {
+          "appnexus": {
+            "placementId": 12883451
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 300
+            }
+          ]
+        }
+      }
+    ],
+    "regs": {
+      "gpp": "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1NYN",
+      "gpp_sid": [6],
+      "gdpr": 1,
+      "ext": {
+        "us_privacy": "1YYY"
+      }
+    },
+    "user": {
+      "consent": "CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA",
+      "ext": {}
+    }
+  },
+  "expectedBidResponse": {
+      "id":"b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+      "bidid":"test bid id",
+      "nbr":0
+  },
+  "expectedReturnCode": 200
+}
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/gdpr-conflict2.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/gdpr-conflict2.json
new file mode 100644
index 00000000..2102a8cd
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/gdpr-conflict2.json
@@ -0,0 +1,56 @@
+{
+  "description": "Well formed amp request with conflicting (2.6 gdpr consent vs. GPP) gdpr consent strings",
+  "mockBidRequest": {
+    "id": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "a3de7af2-a86a-4043-a77b-c7e86744155e"
+      }
+    },
+    "source": {
+      "tid": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5"
+    },
+    "tmax": 1000,
+    "imp": [
+      {
+        "id": "/19968336/header-bid-tag-0",
+        "ext": {
+          "appnexus": {
+            "placementId": 12883451
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 300
+            }
+          ]
+        }
+      }
+    ],
+    "regs": {
+      "gpp": "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1NYN",
+      "gpp_sid": [2,6],
+      "gdpr": 1,
+      "ext": {
+        "us_privacy": "1YYY"
+      }
+    },
+    "user": {
+      "consent": "Invalid",
+      "ext": {}
+    }
+  },
+  "expectedBidResponse": {
+      "id":"b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+      "bidid":"test bid id",
+      "nbr":0
+  },
+  "expectedReturnCode": 200
+}
diff --git a/endpoints/openrtb2/sample-requests/valid-whole/supplementary/us-privacy-conflict.json b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/us-privacy-conflict.json
new file mode 100644
index 00000000..dbf88717
--- /dev/null
+++ b/endpoints/openrtb2/sample-requests/valid-whole/supplementary/us-privacy-conflict.json
@@ -0,0 +1,55 @@
+{
+  "description": "Well formed amp request with conflicting (openrtb 2.6 vs. GPP) CCPA consent values",
+  "mockBidRequest": {
+    "id": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+    "site": {
+      "page": "prebid.org",
+      "publisher": {
+        "id": "a3de7af2-a86a-4043-a77b-c7e86744155e"
+      }
+    },
+    "source": {
+      "tid": "b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5"
+    },
+    "tmax": 1000,
+    "imp": [
+      {
+        "id": "/19968336/header-bid-tag-0",
+        "ext": {
+          "appnexus": {
+            "placementId": 12883451
+          }
+        },
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 300
+            }
+          ]
+        }
+      }
+    ],
+    "regs": {
+      "gpp": "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1NYN",
+      "gpp_sid": [6],
+      "us_privacy": "1YYY",
+      "ext": {
+        "us_privacy": "1YYY"
+      }
+    },
+    "user": {
+      "ext": {}
+    }
+  },
+  "expectedBidResponse": {
+      "id":"b9c97a4b-cbc4-483d-b2c4-58a19ed5cfc5",
+      "bidid":"test bid id",
+      "nbr":0
+  },
+  "expectedReturnCode": 200
+}
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/privacy/ccpa/policy.go b/privacy/ccpa/policy.go
index 6576e2b7..e2da5e12 100644
--- a/privacy/ccpa/policy.go
+++ b/privacy/ccpa/policy.go
@@ -6,6 +6,7 @@ import (
 	gpplib "github.com/prebid/go-gpp"
 	gppConstants "github.com/prebid/go-gpp/constants"
 	"github.com/prebid/openrtb/v17/openrtb2"
+	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
@@ -19,7 +20,13 @@ type Policy struct {
 func ReadFromRequestWrapper(req *openrtb_ext.RequestWrapper, gpp gpplib.GppContainer) (Policy, error) {
 	var consent string
 	var noSaleBidders []string
-	if req.BidRequest != nil && req.BidRequest.Regs != nil {
+	var warn error = nil
+
+	if req == nil || req.BidRequest == nil {
+		return Policy{}, nil
+	}
+
+	if req.BidRequest.Regs != nil {
 		for _, s := range req.BidRequest.Regs.GPPSID {
 			if s == int8(gppConstants.SectionUSPV1) {
 				for i, id := range gpp.SectionTypes {
@@ -29,13 +36,18 @@ func ReadFromRequestWrapper(req *openrtb_ext.RequestWrapper, gpp gpplib.GppConta
 				}
 			}
 		}
+		if req.BidRequest.Regs.USPrivacy != "" {
+			if consent == "" {
+				consent = req.BidRequest.Regs.USPrivacy
+			} else if consent != req.BidRequest.Regs.USPrivacy {
+				warn = &errortypes.Warning{
+					Message:     "regs.us_privacy consent does not match uspv1 in GPP, using regs.gpp",
+					WarningCode: errortypes.InvalidPrivacyConsentWarningCode}
+			}
+		}
 	}
 
 	if consent == "" {
-		if req == nil {
-			return Policy{}, nil
-		}
-
 		// Read consent from request.regs.ext
 		regsExt, err := req.GetRegExt()
 		if err != nil {
@@ -55,7 +67,7 @@ func ReadFromRequestWrapper(req *openrtb_ext.RequestWrapper, gpp gpplib.GppConta
 		noSaleBidders = reqPrebid.NoSale
 	}
 
-	return Policy{consent, noSaleBidders}, nil
+	return Policy{consent, noSaleBidders}, warn
 }
 
 func ReadFromRequest(req *openrtb2.BidRequest) (Policy, error) {
diff --git a/static/bidder-info/between.yaml b/static/bidder-info/between.yaml
index cf5ce25b..15ad9eaf 100644
--- a/static/bidder-info/between.yaml
+++ b/static/bidder-info/between.yaml
@@ -11,6 +11,6 @@ capabilities:
       - banner
 userSync:
   redirect:
-    url: "https://ads.betweendigital.com/match?bidder_id=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback_url={{.RedirectURL}}"
+    url: "https://ads.betweendigital.com/match?bidder_id=pbs&gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback_url={{.RedirectURL}}"
     userMacro: "${USER_ID}"
 
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/adnuntius/adnuntiustest/supplemental/check-dealId.json b/adapters/adnuntius/adnuntiustest/supplemental/check-dealId.json
new file mode 100644
index 00000000..2565fee9
--- /dev/null
+++ b/adapters/adnuntius/adnuntiustest/supplemental/check-dealId.json
@@ -0,0 +1,102 @@
+{
+  "mockBidRequest": {
+      "id": "test-request-id",
+      "site": {
+          "page": "prebid.org"
+      },
+      "imp": [
+          {
+              "id": "test-imp-id",
+              "banner": {
+                  "format": [
+                      {
+                          "w": 300,
+                          "h": 250
+                      },
+                      {
+                          "w": 300,
+                          "h": 600
+                      }
+                  ]
+              },
+              "ext": {
+                  "bidder": {
+                      "auId": "123"
+                  }
+              }
+          }
+      ]
+  },
+
+  "httpCalls": [
+      {
+          "expectedRequest": {
+              "uri": "http://whatever.url?format=json&tzo=0",
+              "body": {
+                  "adUnits": [
+                      {
+                          "auId": "123",
+                          "targetId": "123-test-imp-id",
+            "dimensions": [[300,250],[300,600]]
+                      }
+                  ],
+                  "context": "prebid.org",
+                  "metaData": {}
+              }
+          },
+          "mockResponse": {
+              "status": 200,
+              "body": {
+                  "adUnits": [
+                      {
+                          "auId": "0000000000000123",
+                          "targetId": "123-test-imp-id",
+                          "html": "<ADCODE>",
+                          "responseId": "adn-rsp-900646517",
+                          "ads": [
+                              {
+                                  "destinationUrls": {
+                                      "url": "http://www.google.com"
+                                  },
+                                  "bid": {
+                                      "amount": 20.0,
+                                      "currency": "NOK"
+                                  },
+                                  "adId": "adn-id-1559784094",
+                                  "creativeWidth": "980",
+                                  "creativeHeight": "240",
+                                  "dealId":"deal_123",
+                                  "creativeId": "jn9hpzvlsf8cpdmm",
+                                  "lineItemId": "q7y9qm5b0xt9htrv"
+                              }
+                          ]
+                      }
+                  ]
+              }
+          }
+      }
+  ],
+  "expectedBidResponses": [
+      {
+          "bids": [
+              {
+                  "bid": {
+                      "id": "adn-id-1559784094",
+                      "impid": "test-imp-id",
+                      "price": 20000,
+                      "adm": "<ADCODE>",
+                      "adid": "adn-id-1559784094",
+                      "adomain": ["google.com"],
+                      "dealid" : "deal_123",
+                      "cid": "q7y9qm5b0xt9htrv",
+                      "crid": "jn9hpzvlsf8cpdmm",
+                      "w": 980,
+                      "h": 240
+                  },
+                  "type": "banner"
+              }
+          ],
+          "currency": "NOK"
+      }
+  ]
+}
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/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index 3c198fbe..43dac63d 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -3529,7 +3529,32 @@ func TestIOS14EndToEnd(t *testing.T) {
 }
 
 func TestAuctionWarnings(t *testing.T) {
-	reqBody := validRequest(t, "us-privacy-invalid.json")
+	testCases := []struct {
+		name            string
+		file            string
+		expectedWarning string
+	}{
+		{
+			name:            "us-privacy-invalid",
+			file:            "us-privacy-invalid.json",
+			expectedWarning: "CCPA consent is invalid and will be ignored. (request.regs.ext.us_privacy must contain 4 characters)",
+		},
+		{
+			name:            "us-privacy-signals-conflict",
+			file:            "us-privacy-conflict.json",
+			expectedWarning: "regs.us_privacy consent does not match uspv1 in GPP, using regs.gpp",
+		},
+		{
+			name:            "gdpr-signals-conflict", // gdpr signals do not match
+			file:            "gdpr-conflict.json",
+			expectedWarning: "regs.gdpr signal conflicts with GPP (regs.gpp_sid) and will be ignored",
+		},
+		{
+			name:            "gdpr-signals-conflict2", // gdpr consent strings do not match
+			file:            "gdpr-conflict2.json",
+			expectedWarning: "user.consent GDPR string conflicts with GPP (regs.gpp) GDPR string, using regs.gpp",
+		},
+	}
 	deps := &endpointDeps{
 		fakeUUIDGenerator{},
 		&warningsCheckExchange{},
@@ -3537,7 +3562,7 @@ func TestAuctionWarnings(t *testing.T) {
 		&mockStoredReqFetcher{},
 		empty_fetcher.EmptyFetcher{},
 		empty_fetcher.EmptyFetcher{},
-		&config.Configuration{MaxRequestSize: int64(len(reqBody))},
+		&config.Configuration{MaxRequestSize: maxSize},
 		&metricsConfig.NilMetricsEngine{},
 		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
 		map[string]string{},
@@ -3550,24 +3575,27 @@ func TestAuctionWarnings(t *testing.T) {
 		empty_fetcher.EmptyFetcher{},
 		hookexecution.NewHookExecutor(hooks.EmptyPlanBuilder{}, hookexecution.EndpointAuction, &metricsConfig.NilMetricsEngine{}),
 	}
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			reqBody := validRequest(t, test.file)
+			req := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(reqBody))
+			recorder := httptest.NewRecorder()
 
-	req := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(reqBody))
-	recorder := httptest.NewRecorder()
+			deps.Auction(recorder, req, nil)
 
-	deps.Auction(recorder, req, nil)
+			if recorder.Code != http.StatusOK {
+				t.Errorf("Endpoint should return a 200")
+			}
+			warnings := deps.ex.(*warningsCheckExchange).auctionRequest.Warnings
+			if !assert.Len(t, warnings, 1, "One warning should be returned from exchange") {
+				t.FailNow()
+			}
+			actualWarning := warnings[0].(*errortypes.Warning)
+			assert.Equal(t, test.expectedWarning, actualWarning.Message, "Warning message is incorrect")
 
-	if recorder.Code != http.StatusOK {
-		t.Errorf("Endpoint should return a 200")
-	}
-	warnings := deps.ex.(*warningsCheckExchange).auctionRequest.Warnings
-	if !assert.Len(t, warnings, 1, "One warning should be returned from exchange") {
-		t.FailNow()
+			assert.Equal(t, errortypes.InvalidPrivacyConsentWarningCode, actualWarning.WarningCode, "Warning code is incorrect")
+		})
 	}
-	actualWarning := warnings[0].(*errortypes.Warning)
-	expectedMessage := "CCPA consent is invalid and will be ignored. (request.regs.ext.us_privacy must contain 4 characters)"
-	assert.Equal(t, expectedMessage, actualWarning.Message, "Warning message is incorrect")
-
-	assert.Equal(t, errortypes.InvalidPrivacyConsentWarningCode, actualWarning.WarningCode, "Warning code is incorrect")
 }
 
 func TestParseRequestParseImpInfoError(t *testing.T) {
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/privacy/ccpa/policy_test.go b/privacy/ccpa/policy_test.go
index 1e87305e..3deb3329 100644
--- a/privacy/ccpa/policy_test.go
+++ b/privacy/ccpa/policy_test.go
@@ -183,6 +183,33 @@ func TestReadFromRequestWrapper(t *testing.T) {
 				NoSaleBidders: []string{"a", "b"},
 			},
 		},
+		{
+			description: "GPP Success, has regs.us_privacy",
+			request: &openrtb2.BidRequest{
+				Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~present",
+					GPPSID:    []int8{6},
+					USPrivacy: "conflicting"},
+				Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`),
+			},
+			giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{6}, Sections: []gpplib.Section{&upsv1Section}},
+			expectedPolicy: Policy{
+				Consent:       "present",
+				NoSaleBidders: []string{"a", "b"},
+			},
+			expectedError: true,
+		},
+		{
+			description: "Has regs.us_privacy",
+			request: &openrtb2.BidRequest{
+				Regs: &openrtb2.Regs{USPrivacy: "present"},
+				Ext:  json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`),
+			},
+			expectedPolicy: Policy{
+				Consent:       "present",
+				NoSaleBidders: []string{"a", "b"},
+			},
+			expectedError: false,
+		},
 		{
 			description: "GPP Success, no USPV1",
 			request: &openrtb2.BidRequest{
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)
 	}
 }