Repository: prebid/prebid-server
Pull request #2115 (2021-12-20 13:33:40)

Huaweiads - 1. add the corresponding site endpoint selection 2. add package name replacement
update huaweiads adapter
1. add the corresponding site endpoint selection 
2. add package name replacement

hhhjort: I just want to confirm that you have a reason for routing bid requests to a server based on the location of the of the person viewing the ad rather than the location of the PBS server. The common case we see is putting the endpoint an instance of PBS should use in the PBS config rather than calculating it on the fly as you are doing. Host based config has the advantage of, if the PBS instance is located a long distance from the actual user, you don't then make an equally long call from PBS to the bidder when there is a local bidder available.

For example, if a PBS host has instances set up in both Germany and Singapore, but due to some outage a user in France is routed to the Singapore PBS instance, it may be more efficient to have that PBS instance talk to your asian endpoint rather than your european endpoint.

However if you have your endpoints optimized for local demand, it does make sense to route the requests based on user location rather than PBS host location.
mansinahar: @wwwyyy Friendly reminder about the above comments whenever you get a chance. Thanks!
wwwyyy: > I just want to confirm that you have a reason for routing bid requests to a server based on the location of the of the person viewing the ad rather than the location of the PBS server. The common case we see is putting the endpoint an instance of PBS should use in the PBS config rather than calculating it on the fly as you are doing. Host based config has the advantage of, if the PBS instance is located a long distance from the actual user, you don't then make an equally long call from PBS to the bidder when there is a local bidder available.
> 
> For example, if a PBS host has instances set up in both Germany and Singapore, but due to some outage a user in France is routed to the Singapore PBS instance, it may be more efficient to have that PBS instance talk to your asian endpoint rather than your european endpoint.
> 
> However if you have your endpoints optimized for local demand, it does make sense to route the requests based on user location rather than PBS host location.


wwwyyy: > I just want to confirm that you have a reason for routing bid requests to a server based on the location of the of the person viewing the ad rather than the location of the PBS server. The common case we see is putting the endpoint an instance of PBS should use in the PBS config rather than calculating it on the fly as you are doing. Host based config has the advantage of, if the PBS instance is located a long distance from the actual user, you don't then make an equally long call from PBS to the bidder when there is a local bidder available.
> 
> For example, if a PBS host has instances set up in both Germany and Singapore, but due to some outage a user in France is routed to the Singapore PBS instance, it may be more efficient to have that PBS instance talk to your asian endpoint rather than your european endpoint.
> 
> However if you have your endpoints optimized for local demand, it does make sense to route the requests based on user location rather than PBS host location.

 we are testing with clients, considering privacy concerns, and at the same time，
the data cannot be transferred across sites, and the country will correspond to the determined site，so make changes like this
wwwyyy: > @wwwyyy Friendly reminder about the above comments whenever you get a chance. Thanks!

Thank you, the issues in the code has been corrected, please check, thank you very much for your suggestions

Patch:
diff --git a/adapters/adagio/adagio.go b/adapters/adagio/adagio.go
deleted file mode 100644
index 0da4d6ac..00000000
--- a/adapters/adagio/adagio.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package adagio
-
-import (
-	"bytes"
-	"compress/gzip"
-	"encoding/json"
-	"fmt"
-	"github.com/mxmCherry/openrtb/v15/openrtb2"
-	"github.com/prebid/prebid-server/adapters"
-	"github.com/prebid/prebid-server/config"
-	"github.com/prebid/prebid-server/errortypes"
-	"github.com/prebid/prebid-server/openrtb_ext"
-	"net/http"
-)
-
-// Builder builds a new instance of the Adagio adapter for the given bidder with the given config.
-func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
-	bidder := &adapter{
-		endpoint: config.Endpoint,
-	}
-	return bidder, nil
-}
-
-type adapter struct {
-	endpoint string
-}
-
-type extBid struct {
-	Prebid *openrtb_ext.ExtBidPrebid
-}
-
-// MakeRequests prepares the HTTP requests which should be made to fetch bids.
-func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
-	json, err := json.Marshal(request)
-	if err != nil {
-		return nil, []error{err}
-	}
-
-	headers := http.Header{}
-	headers.Add("Content-Type", "application/json;charset=utf-8")
-	headers.Add("Accept", "application/json")
-
-	if request.Device != nil {
-		if len(request.Device.IPv6) > 0 {
-			headers.Add("X-Forwarded-For", request.Device.IPv6)
-		}
-		if len(request.Device.IP) > 0 {
-			headers.Add("X-Forwarded-For", request.Device.IP)
-		}
-	}
-
-	if request.Test == 0 {
-		// Gzip the body
-		// Note: Gzipping could be handled natively later: https://github.com/prebid/prebid-server/issues/1812
-		var bodyBuf bytes.Buffer
-		gz := gzip.NewWriter(&bodyBuf)
-		if _, err = gz.Write(json); err == nil {
-			if err = gz.Close(); err == nil {
-				json = bodyBuf.Bytes()
-				headers.Add("Content-Encoding", "gzip")
-				// /!\ Go already sets the `Accept-Encoding: gzip` header. Never add it manually, or Go won't decompress the response.
-				//headers.Add("Accept-Encoding", "gzip")
-			}
-		}
-	}
-
-	requestToBidder := &adapters.RequestData{
-		Method:  "POST",
-		Uri:     a.endpoint,
-		Body:    json,
-		Headers: headers,
-	}
-
-	return []*adapters.RequestData{requestToBidder}, nil
-}
-
-const unexpectedStatusCodeFormat = "Unexpected status code: %d. Run with request.debug = 1 for more info"
-
-// MakeBids unpacks the server's response into Bids.
-func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, _ *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
-	switch response.StatusCode {
-	case http.StatusOK:
-		break
-	case http.StatusNoContent:
-		return nil, nil
-	case http.StatusServiceUnavailable:
-		fallthrough
-	case http.StatusBadRequest:
-		fallthrough
-	case http.StatusUnauthorized:
-		fallthrough
-	case http.StatusForbidden:
-		err := &errortypes.BadInput{
-			Message: fmt.Sprintf(unexpectedStatusCodeFormat, response.StatusCode),
-		}
-		return nil, []error{err}
-	default:
-		err := &errortypes.BadServerResponse{
-			Message: fmt.Sprintf(unexpectedStatusCodeFormat, response.StatusCode),
-		}
-		return nil, []error{err}
-	}
-
-	var openRTBBidderResponse openrtb2.BidResponse
-	if err := json.Unmarshal(response.Body, &openRTBBidderResponse); err != nil {
-		return nil, []error{err}
-	}
-
-	bidsCapacity := len(internalRequest.Imp)
-	errs := make([]error, 0, bidsCapacity)
-	bidderResponse := adapters.NewBidderResponseWithBidsCapacity(bidsCapacity)
-	var typedBid *adapters.TypedBid
-	for _, seatBid := range openRTBBidderResponse.SeatBid {
-		for _, bid := range seatBid.Bid {
-			activeBid := bid
-
-			activeExt := &extBid{}
-			if err := json.Unmarshal(activeBid.Ext, activeExt); err != nil {
-				errs = append(errs, err)
-			}
-
-			var bidType openrtb_ext.BidType
-			if activeExt.Prebid != nil && activeExt.Prebid.Type != "" {
-				bidType = activeExt.Prebid.Type
-			} else {
-				err := &errortypes.BadServerResponse{
-					Message: fmt.Sprintf("Failed to find native/banner/video mediaType \"%s\" ", activeBid.ImpID),
-				}
-				errs = append(errs, err)
-				continue
-			}
-
-			typedBid = &adapters.TypedBid{Bid: &activeBid, BidType: bidType}
-			bidderResponse.Bids = append(bidderResponse.Bids, typedBid)
-		}
-	}
-
-	return bidderResponse, nil
-}
diff --git a/adapters/algorix/algorix.go b/adapters/algorix/algorix.go
index 628207d6..d24521b4 100644
--- a/adapters/algorix/algorix.go
+++ b/adapters/algorix/algorix.go
@@ -19,6 +19,14 @@ type adapter struct {
 	EndpointTemplate *template.Template
 }
 
+type algorixVideoExt struct {
+	Rewarded int `json:"rewarded"`
+}
+
+type algorixResponseBidExt struct {
+	MediaType string `json:"mediaType"`
+}
+
 // Builder builds a new instance of the AlgoriX adapter for the given bidder with the given config.
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
 	endpoint, err := template.New("endpointTemplate").Parse(config.Endpoint)
@@ -121,6 +129,19 @@ func preProcess(request *openrtb2.BidRequest) {
 				request.Imp[i].Banner = &banner
 			}
 		}
+		if request.Imp[i].Video != nil {
+			var impExt adapters.ExtImpBidder
+			err := json.Unmarshal(request.Imp[i].Ext, &impExt)
+			if err != nil {
+				continue
+			}
+			if impExt.Prebid != nil && impExt.Prebid.IsRewardedInventory == 1 {
+				videoCopy := *request.Imp[i].Video
+				videoExt := algorixVideoExt{Rewarded: 1}
+				videoCopy.Ext, err = json.Marshal(&videoExt)
+				request.Imp[i].Video = &videoCopy
+			}
+		}
 	}
 }
 
@@ -147,32 +168,58 @@ func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest
 	}
 
 	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+	var errs []error
 
 	for _, seatBid := range bidResp.SeatBid {
 		for idx := range seatBid.Bid {
-			mediaType := getBidType(seatBid.Bid[idx].ImpID, internalRequest.Imp)
-			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
-				Bid:     &seatBid.Bid[idx],
-				BidType: mediaType,
-			})
+			mediaType, err := getBidType(seatBid.Bid[idx], internalRequest.Imp)
+			if err != nil {
+				errs = append(errs, err)
+			} else {
+				bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+					Bid:     &seatBid.Bid[idx],
+					BidType: mediaType,
+				})
+			}
 		}
 	}
-	return bidResponse, nil
+
+	return bidResponse, errs
 }
 
-func getBidType(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
+func getBidType(bid openrtb2.Bid, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
+	var bidExt algorixResponseBidExt
+	err := json.Unmarshal(bid.Ext, &bidExt)
+	if err == nil {
+		switch bidExt.MediaType {
+		case "banner":
+			return openrtb_ext.BidTypeBanner, nil
+		case "native":
+			return openrtb_ext.BidTypeNative, nil
+		case "video":
+			return openrtb_ext.BidTypeVideo, nil
+		}
+	}
+	var mediaType openrtb_ext.BidType
+	var typeCnt = 0
 	for _, imp := range imps {
-		if imp.ID == impId {
+		if imp.ID == bid.ImpID {
 			if imp.Banner != nil {
-				break
+				typeCnt += 1
+				mediaType = openrtb_ext.BidTypeBanner
 			}
 			if imp.Native != nil {
-				return openrtb_ext.BidTypeNative
+				typeCnt += 1
+				mediaType = openrtb_ext.BidTypeNative
 			}
 			if imp.Video != nil {
-				return openrtb_ext.BidTypeVideo
+				typeCnt += 1
+				mediaType = openrtb_ext.BidTypeVideo
 			}
 		}
 	}
-	return openrtb_ext.BidTypeBanner
+	if typeCnt == 1 {
+		return mediaType, nil
+	}
+	return mediaType, fmt.Errorf("unable to fetch mediaType in multi-format: %s", bid.ImpID)
 }
diff --git a/adapters/huaweiads/huaweiads.go b/adapters/huaweiads/huaweiads.go
index 39484422..f8acb2b9 100644
--- a/adapters/huaweiads/huaweiads.go
+++ b/adapters/huaweiads/huaweiads.go
@@ -30,6 +30,10 @@ const defaultUnknownNetworkType = 0
 const timeFormat = "2006-01-02 15:04:05.000"
 const defaultTimeZone = "+0200"
 const defaultModelName = "HUAWEI"
+const chineseSiteEndPoint = "https://acd.op.hicloud.com/ppsadx/getResult"
+const europeanSiteEndPoint = "https://adx-dre.op.hicloud.com/ppsadx/getResult"
+const asianSiteEndPoint = "https://adx-dra.op.hicloud.com/ppsadx/getResult"
+const russianSiteEndPoint = "https://adx-drru.op.hicloud.com/ppsadx/getResult"
 
 // creative type
 const (
@@ -228,7 +232,24 @@ type monitor struct {
 }
 
 type adapter struct {
-	endpoint string
+	endpoint  string
+	extraInfo ExtraInfo
+}
+
+type ExtraInfo struct {
+	PkgNameConvert              []pkgNameConvert `json:"pkgNameConvert,omitempty"`
+	CloseSiteSelectionByCountry string           `json:"closeSiteSelectionByCountry,omitempty"`
+}
+
+type pkgNameConvert struct {
+	ConvertedPkgName           string   `json:"convertedPkgName,omitempty"`
+	UnconvertedPkgNames        []string `json:"unconvertedPkgNames,omitempty"`
+	UnconvertedPkgNameKeyWords []string `json:"unconvertedPkgNameKeyWords,omitempty"`
+	UnconvertedPkgNamePrefixs  []string `json:"unconvertedPkgNamePrefixs,omitempty"`
+	ExceptionPkgNames          []string `json:"exceptionPkgNames,omitempty"`
+}
+
+type empty struct {
 }
 
 func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest,
@@ -260,7 +281,8 @@ func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest,
 	}
 	request.Multislot = multislot
 
-	if err := getHuaweiAdsReqJson(&request, openRTBRequest, huaweiAdsImpExt); err != nil {
+	countryCode, err := getHuaweiAdsReqJson(&request, openRTBRequest, huaweiAdsImpExt, a.extraInfo)
+	if err != nil {
 		return nil, []error{err}
 	}
 
@@ -278,7 +300,7 @@ func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest,
 	header = getHeaders(huaweiAdsImpExt, openRTBRequest, isTestAuthorization)
 	bidRequest := &adapters.RequestData{
 		Method:  http.MethodPost,
-		Uri:     a.endpoint,
+		Uri:     getFinalEndPoint(countryCode, a.endpoint, a.extraInfo),
 		Body:    reqJSON,
 		Headers: header,
 	}
@@ -286,6 +308,37 @@ func (a *adapter) MakeRequests(openRTBRequest *openrtb2.BidRequest,
 	return []*adapters.RequestData{bidRequest}, nil
 }
 
+// countryCode is alpha2, choose the corresponding site end point
+func getFinalEndPoint(countryCode string, defaultEndpoint string, extraInfo ExtraInfo) string {
+	// closeSiteSelectionByCountry == 1, close site selection, use the defaultEndpoint
+	if "1" == extraInfo.CloseSiteSelectionByCountry {
+		return defaultEndpoint
+	}
+
+	if countryCode == "" || len(countryCode) > 2 {
+		return defaultEndpoint
+	}
+	var europeanSiteCountryCodeGroup = map[string]empty{"AX": {}, "AL": {}, "AD": {}, "AU": {}, "AT": {}, "BE": {},
+		"BA": {}, "BG": {}, "CA": {}, "HR": {}, "CY": {}, "CZ": {}, "DK": {}, "EE": {}, "FO": {}, "FI": {},
+		"FR": {}, "DE": {}, "GI": {}, "GR": {}, "GL": {}, "GG": {}, "VA": {}, "HU": {}, "IS": {}, "IE": {},
+		"IM": {}, "IL": {}, "IT": {}, "JE": {}, "YK": {}, "LV": {}, "LI": {}, "LT": {}, "LU": {}, "MT": {},
+		"MD": {}, "MC": {}, "ME": {}, "NL": {}, "AN": {}, "NZ": {}, "NO": {}, "PL": {}, "PT": {}, "RO": {},
+		"MF": {}, "VC": {}, "SM": {}, "RS": {}, "SX": {}, "SK": {}, "SI": {}, "ES": {}, "SE": {}, "CH": {},
+		"TR": {}, "UA": {}, "GB": {}, "US": {}, "MK": {}, "SJ": {}, "BQ": {}, "PM": {}, "CW": {}}
+	var russianSiteCountryCodeGroup = map[string]empty{"RU": {}}
+	var chineseSiteCountryCodeGroup = map[string]empty{"CN": {}}
+	// choose site
+	if _, exists := chineseSiteCountryCodeGroup[countryCode]; exists {
+		return chineseSiteEndPoint
+	} else if _, exists := russianSiteCountryCodeGroup[countryCode]; exists {
+		return russianSiteEndPoint
+	} else if _, exists := europeanSiteCountryCodeGroup[countryCode]; exists {
+		return europeanSiteEndPoint
+	} else {
+		return asianSiteEndPoint
+	}
+}
+
 func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData,
 	bidderRawResponse *adapters.ResponseData) (bidderResponse *adapters.BidderResponse, errs []error) {
 	httpStatusError := checkRespStatusCode(bidderRawResponse)
@@ -314,12 +367,52 @@ func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder
 
 // Builder builds a new instance of the HuaweiAds adapter for the given bidder with the given config.
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	extraInfo, err := getExtraInfo(config.ExtraAdapterInfo)
+	if err != nil {
+		return nil, err
+	}
+
 	bidder := &adapter{
-		endpoint: config.Endpoint,
+		endpoint:  config.Endpoint,
+		extraInfo: extraInfo,
 	}
 	return bidder, nil
 }
 
+func getExtraInfo(v string) (ExtraInfo, error) {
+	var extraInfo ExtraInfo
+	if len(v) == 0 {
+		return extraInfo, nil
+	}
+
+	if err := json.Unmarshal([]byte(v), &extraInfo); err != nil {
+		return extraInfo, fmt.Errorf("invalid extra info: %v , pls check", err)
+	}
+
+	for _, convert := range extraInfo.PkgNameConvert {
+		if convert.ConvertedPkgName == "" {
+			return extraInfo, fmt.Errorf("invalid extra info: ConvertedPkgName is empty, pls check")
+		}
+
+		if convert.UnconvertedPkgNameKeyWords != nil {
+			for _, keyword := range convert.UnconvertedPkgNameKeyWords {
+				if keyword == "" {
+					return extraInfo, fmt.Errorf("invalid extra info: UnconvertedPkgNameKeyWords has a empty keyword, pls check")
+				}
+			}
+		}
+
+		if convert.UnconvertedPkgNamePrefixs != nil {
+			for _, prefix := range convert.UnconvertedPkgNamePrefixs {
+				if prefix == "" {
+					return extraInfo, fmt.Errorf("invalid extra info: UnconvertedPkgNamePrefixs has a empty value, pls check")
+				}
+			}
+		}
+	}
+	return extraInfo, nil
+}
+
 // getHeaders: get request header, Authorization -> digest
 func getHeaders(huaweiAdsImpExt *openrtb_ext.ExtImpHuaweiAds, request *openrtb2.BidRequest, isTestAuthorization bool) http.Header {
 	headers := http.Header{}
@@ -337,19 +430,19 @@ func getHeaders(huaweiAdsImpExt *openrtb_ext.ExtImpHuaweiAds, request *openrtb2.
 }
 
 // getHuaweiAdsReqJson: get body json for HuaweiAds request
-func getHuaweiAdsReqJson(request *huaweiAdsRequest, openRTBRequest *openrtb2.BidRequest, huaweiAdsImpExt *openrtb_ext.ExtImpHuaweiAds) error {
+func getHuaweiAdsReqJson(request *huaweiAdsRequest, openRTBRequest *openrtb2.BidRequest,
+	huaweiAdsImpExt *openrtb_ext.ExtImpHuaweiAds, extraInfo ExtraInfo) (countryCode string, err error) {
 	request.Version = huaweiAdxApiVersion
-	var err error
-	if err = getHuaweiAdsReqAppInfo(request, openRTBRequest); err != nil {
-		return err
+	if countryCode, err = getHuaweiAdsReqAppInfo(request, openRTBRequest, extraInfo); err != nil {
+		return "", err
 	}
 	if err = getHuaweiAdsReqDeviceInfo(request, openRTBRequest, huaweiAdsImpExt); err != nil {
-		return err
+		return "", err
 	}
 	getHuaweiAdsReqNetWorkInfo(request, openRTBRequest)
 	getHuaweiAdsReqRegsInfo(request, openRTBRequest)
 	getHuaweiAdsReqGeoInfo(request, openRTBRequest)
-	return nil
+	return countryCode, nil
 }
 
 func getHuaweiAdsReqAdslot30(huaweiAdsImpExt *openrtb_ext.ExtImpHuaweiAds,
@@ -459,7 +552,7 @@ func convertAdtypeString2Integer(adtypeLower string) int32 {
 }
 
 // getHuaweiAdsReqAppInfo: get app information for HuaweiAds request
-func getHuaweiAdsReqAppInfo(request *huaweiAdsRequest, openRTBRequest *openrtb2.BidRequest) error {
+func getHuaweiAdsReqAppInfo(request *huaweiAdsRequest, openRTBRequest *openrtb2.BidRequest, extraInfo ExtraInfo) (countryCode string, err error) {
 	var app app
 	if openRTBRequest.App != nil {
 		if openRTBRequest.App.Ver != "" {
@@ -471,9 +564,9 @@ func getHuaweiAdsReqAppInfo(request *huaweiAdsRequest, openRTBRequest *openrtb2.
 
 		// bundle cannot be empty, we need package name.
 		if openRTBRequest.App.Bundle != "" {
-			app.Pkgname = openRTBRequest.App.Bundle
+			app.Pkgname = getFinalPkgName(openRTBRequest.App.Bundle, extraInfo)
 		} else {
-			return errors.New("HuaweiAdsReqApp: Pkgname is empty.")
+			return "", errors.New("HuaweiAdsReqApp: Pkgname is empty.")
 		}
 
 		if openRTBRequest.App.Content != nil && openRTBRequest.App.Content.Language != "" {
@@ -482,9 +575,48 @@ func getHuaweiAdsReqAppInfo(request *huaweiAdsRequest, openRTBRequest *openrtb2.
 			app.Lang = "en"
 		}
 	}
-	app.Country = getCountryCode(openRTBRequest)
+	countryCode = getCountryCode(openRTBRequest)
+	app.Country = countryCode
 	request.App = app
-	return nil
+	return countryCode, nil
+}
+
+// when it has pkgNameConvert (include different rules)
+// 1. when bundleName in ExceptionPkgNames, finalPkgname = bundleName
+// 2. when bundleName conform UnconvertedPkgNames, finalPkgname = ConvertedPkgName
+// 3. when bundleName conform keyword, finalPkgname = ConvertedPkgName
+// 4. when bundleName conform prefix, finalPkgname = ConvertedPkgName
+func getFinalPkgName(bundleName string, extraInfo ExtraInfo) string {
+	for _, convert := range extraInfo.PkgNameConvert {
+		if convert.ConvertedPkgName == "" {
+			continue
+		}
+
+		for _, name := range convert.ExceptionPkgNames {
+			if name == bundleName {
+				return bundleName
+			}
+		}
+
+		for _, name := range convert.UnconvertedPkgNames {
+			if name == bundleName || name == "*" {
+				return convert.ConvertedPkgName
+			}
+		}
+
+		for _, keyword := range convert.UnconvertedPkgNameKeyWords {
+			if strings.Index(bundleName, keyword) > 0 {
+				return convert.ConvertedPkgName
+			}
+		}
+
+		for _, prefix := range convert.UnconvertedPkgNamePrefixs {
+			if strings.HasPrefix(bundleName, prefix) {
+				return convert.ConvertedPkgName
+			}
+		}
+	}
+	return bundleName
 }
 
 // getClientTime: get field clientTime, format: 2006-01-02 15:04:05.000+0200
@@ -552,7 +684,12 @@ func convertCountryCode(country string) (out string) {
 	if country == "" {
 		return defaultCountryName
 	}
-	var mapCountryCodeAlpha3ToAlpha2 = map[string]string{"CHL": "CL", "CHN": "CN", "ARE": "AE"}
+	var mapCountryCodeAlpha3ToAlpha2 = map[string]string{"AND": "AD", "AGO": "AO", "AUT": "AT", "BGD": "BD",
+		"BLR": "BY", "CAF": "CF", "TCD": "TD", "CHL": "CL", "CHN": "CN", "COG": "CG", "COD": "CD", "DNK": "DK",
+		"GNQ": "GQ", "EST": "EE", "GIN": "GN", "GNB": "GW", "GUY": "GY", "IRQ": "IQ", "IRL": "IE", "ISR": "IL",
+		"KAZ": "KZ", "LBY": "LY", "MDG": "MG", "MDV": "MV", "MEX": "MX", "MNE": "ME", "MOZ": "MZ", "PAK": "PK",
+		"PNG": "PG", "PRY": "PY", "POL": "PL", "PRT": "PT", "SRB": "RS", "SVK": "SK", "SVN": "SI", "SWE": "SE",
+		"TUN": "TN", "TUR": "TR", "TKM": "TM", "UKR": "UA", "ARE": "AE", "URY": "UY"}
 	if mappedCountry, exists := mapCountryCodeAlpha3ToAlpha2[country]; exists {
 		return mappedCountry
 	}
diff --git a/adapters/vidoomy/vidoomy.go b/adapters/vidoomy/vidoomy.go
new file mode 100644
index 00000000..57fbb09d
--- /dev/null
+++ b/adapters/vidoomy/vidoomy.go
@@ -0,0 +1,173 @@
+package vidoomy
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+func (a adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	var errors []error
+
+	reqs := make([]*adapters.RequestData, 0, len(request.Imp))
+
+	header := getHeaders(request)
+	for _, imp := range request.Imp {
+
+		// Split up multi-impression requests into multiple requests so that
+		// each split request is only associated to a single impression
+		reqCopy := *request
+		reqCopy.Imp = []openrtb2.Imp{imp}
+
+		if err := changeRequestForBidService(&reqCopy); err != nil {
+			errors = append(errors, err)
+			continue
+		}
+
+		reqJSON, err := json.Marshal(&reqCopy)
+		if err != nil {
+			errors = append(errors, err)
+			continue
+		}
+
+		reqs = append(reqs, &adapters.RequestData{
+			Method:  "POST",
+			Uri:     a.endpoint,
+			Body:    reqJSON,
+			Headers: header,
+		})
+	}
+
+	return reqs, errors
+}
+
+func getHeaders(request *openrtb2.BidRequest) http.Header {
+	headers := http.Header{}
+
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("x-openrtb-version", "2.5")
+
+	if request.Device == nil {
+		return headers
+	}
+
+	if request.Device.UA != "" {
+		headers.Set("User-Agent", request.Device.UA)
+	}
+
+	if len(request.Device.IPv6) > 0 {
+		headers.Add("X-Forwarded-For", request.Device.IPv6)
+	}
+
+	if len(request.Device.IP) > 0 {
+		headers.Add("X-Forwarded-For", request.Device.IP)
+	}
+
+	return headers
+}
+
+func changeRequestForBidService(request *openrtb2.BidRequest) error {
+	if request.Imp[0].Banner == nil {
+		return nil
+	}
+
+	banner := *request.Imp[0].Banner
+	request.Imp[0].Banner = &banner
+
+	if banner.W != nil && banner.H != nil {
+		if *banner.W == 0 || *banner.H == 0 {
+			return fmt.Errorf("invalid sizes provided for Banner %d x %d", *banner.W, *banner.H)
+		}
+		return nil
+	}
+
+	if len(banner.Format) == 0 {
+		return fmt.Errorf("no sizes provided for Banner %v", banner.Format)
+	}
+
+	banner.W = openrtb2.Int64Ptr(banner.Format[0].W)
+	banner.H = openrtb2.Int64Ptr(banner.Format[0].H)
+
+	return nil
+}
+
+func (a adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode),
+		}}
+	}
+
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Bad server response: %d.", err),
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(internalRequest.Imp))
+
+	for _, sb := range bidResp.SeatBid {
+		for _, bid := range sb.Bid {
+			bid := bid
+			exists, mediaType := getImpInfo(bid.ImpID, internalRequest.Imp)
+			if !exists {
+				return nil, []error{&errortypes.BadServerResponse{
+					Message: fmt.Sprintf("Unknown ad unit code '%s'", bid.ImpID),
+				}}
+			}
+
+			if openrtb_ext.BidTypeBanner != mediaType &&
+				openrtb_ext.BidTypeVideo != mediaType {
+				//only banner and video are supported, anything else is ignored
+				continue
+			}
+
+			bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+				Bid:     &bid,
+				BidType: mediaType,
+			})
+		}
+	}
+
+	return bidResponse, nil
+}
+
+func getImpInfo(impId string, imps []openrtb2.Imp) (bool, openrtb_ext.BidType) {
+	var mediaType openrtb_ext.BidType
+	for _, imp := range imps {
+		if imp.ID == impId {
+
+			if imp.Video != nil {
+				mediaType = openrtb_ext.BidTypeVideo
+			} else if imp.Banner != nil {
+				mediaType = openrtb_ext.BidTypeBanner
+			}
+
+			return true, mediaType
+		}
+	}
+	return false, mediaType
+}
+
+// Builder builds a new instance of the Vidoomy adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
diff --git a/config/config.go b/config/config.go
index a2413ffe..e7a9effa 100644
--- a/config/config.go
+++ b/config/config.go
@@ -807,7 +807,6 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.33across.partner_id", "")
 	v.SetDefault("adapters.aceex.endpoint", "http://bl-us.aceex.io/?uqhash={{.AccountID}}")
 	v.SetDefault("adapters.acuityads.endpoint", "http://{{.Host}}.admanmedia.com/bid?token={{.AccountID}}")
-	v.SetDefault("adapters.adagio.endpoint", "https://mp.4dex.io/ortb2")
 	v.SetDefault("adapters.adf.endpoint", "https://adx.adform.net/adx/openrtb")
 	v.SetDefault("adapters.adform.endpoint", "https://adx.adform.net/adx/openrtb")
 	v.SetDefault("adapters.adgeneration.endpoint", "https://d.socdm.com/adsv/v1")
@@ -943,6 +942,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.valueimpression.endpoint", "http://useast.quantumdex.io/auction/pbs")
 	v.SetDefault("adapters.verizonmedia.disabled", true)
 	v.SetDefault("adapters.videobyte.endpoint", "https://x.videobyte.com/ortbhb")
+	v.SetDefault("adapters.vidoomy.endpoint", "https://p.vidoomy.com/api/rtbserver/pbs")
 	v.SetDefault("adapters.viewdeos.endpoint", "http://ghb.sync.viewdeos.com/pbs/ortb")
 	v.SetDefault("adapters.visx.endpoint", "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard:0.1.0")
 	v.SetDefault("adapters.vrtcal.endpoint", "http://rtb.vrtcal.com/bidder_prebid.vap?ssp=1804")
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 38b27970..452e7ed5 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -26,6 +26,7 @@ import (
 	"github.com/prebid/prebid-server/stored_requests/backends/empty_fetcher"
 	"github.com/prebid/prebid-server/usersync"
 	"github.com/prebid/prebid-server/util/iputil"
+	"github.com/prebid/prebid-server/version"
 
 	"github.com/buger/jsonparser"
 	"github.com/golang/glog"
@@ -133,6 +134,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
 	// and "Access-Control-Allow-Credentials" are handled in CORS middleware
 	w.Header().Set("AMP-Access-Control-Allow-Source-Origin", origin)
 	w.Header().Set("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin")
+	w.Header().Set("X-Prebid", version.BuildXPrebidHeader(version.Ver))
 
 	req, errL := deps.parseAmpRequest(r)
 	ao.Errors = append(ao.Errors, errL...)
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 4d68db50..3f0a35e8 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -14,6 +14,7 @@ import (
 	"time"
 
 	"github.com/prebid/prebid-server/firstpartydata"
+	"github.com/prebid/prebid-server/version"
 
 	"github.com/buger/jsonparser"
 	jsonpatch "github.com/evanphx/json-patch"
@@ -148,6 +149,8 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
 		deps.analytics.LogAuctionObject(&ao)
 	}()
 
+	w.Header().Set("X-Prebid", version.BuildXPrebidHeader(version.Ver))
+
 	req, impExtInfoMap, errL := deps.parseRequest(r)
 	if errortypes.ContainsFatalError(errL) && writeError(errL, w, &labels) {
 		return
@@ -234,7 +237,6 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
 	enc := json.NewEncoder(w)
 	enc.SetEscapeHTML(false)
 
-	// Fixes #328
 	w.Header().Set("Content-Type", "application/json")
 
 	// If an error happens when encoding the response, there isn't much we can do.
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index cbffe2e3..1f16f92a 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -22,6 +22,7 @@ import (
 	"github.com/prebid/prebid-server/errortypes"
 	"github.com/prebid/prebid-server/util/iputil"
 	"github.com/prebid/prebid-server/util/uuidutil"
+	"github.com/prebid/prebid-server/version"
 
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
@@ -153,6 +154,8 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 		deps.analytics.LogVideoObject(&vo)
 	}()
 
+	w.Header().Set("X-Prebid", version.BuildXPrebidHeader(version.Ver))
+
 	lr := &io.LimitedReader{
 		R: r.Body,
 		N: deps.cfg.MaxRequestSize,
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 8075b7f1..850b41ab 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -5,7 +5,6 @@ import (
 	"github.com/prebid/prebid-server/adapters/33across"
 	"github.com/prebid/prebid-server/adapters/aceex"
 	"github.com/prebid/prebid-server/adapters/acuityads"
-	"github.com/prebid/prebid-server/adapters/adagio"
 	"github.com/prebid/prebid-server/adapters/adf"
 	"github.com/prebid/prebid-server/adapters/adgeneration"
 	"github.com/prebid/prebid-server/adapters/adhese"
@@ -125,6 +124,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/unicorn"
 	"github.com/prebid/prebid-server/adapters/unruly"
 	"github.com/prebid/prebid-server/adapters/videobyte"
+	"github.com/prebid/prebid-server/adapters/vidoomy"
 	"github.com/prebid/prebid-server/adapters/visx"
 	"github.com/prebid/prebid-server/adapters/vrtcal"
 	"github.com/prebid/prebid-server/adapters/yahoossp"
@@ -144,7 +144,6 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.Bidder33Across:          ttx.Builder,
 		openrtb_ext.BidderAceex:             aceex.Builder,
 		openrtb_ext.BidderAcuityAds:         acuityads.Builder,
-		openrtb_ext.BidderAdagio:            adagio.Builder,
 		openrtb_ext.BidderAdf:               adf.Builder,
 		openrtb_ext.BidderAdform:            adf.Builder,
 		openrtb_ext.BidderAdgeneration:      adgeneration.Builder,
@@ -272,6 +271,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderValueImpression:   apacdex.Builder,
 		openrtb_ext.BidderVerizonMedia:      yahoossp.Builder,
 		openrtb_ext.BidderVideoByte:         videobyte.Builder,
+		openrtb_ext.BidderVidoomy:           vidoomy.Builder,
 		openrtb_ext.BidderViewdeos:          adtelligent.Builder,
 		openrtb_ext.BidderVisx:              visx.Builder,
 		openrtb_ext.BidderVrtcal:            vrtcal.Builder,
diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go
index 9ab27561..50308dae 100644
--- a/exchange/adapter_util.go
+++ b/exchange/adapter_util.go
@@ -79,6 +79,7 @@ func GetActiveBidders(infos config.BidderInfos) map[string]openrtb_ext.BidderNam
 func GetDisabledBiddersErrorMessages(infos config.BidderInfos) map[string]string {
 	disabledBidders := map[string]string{
 		"lifestreet": `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+		"adagio":     `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 	}
 
 	for name, info := range infos {
diff --git a/exchange/bidder.go b/exchange/bidder.go
index 2aae63e2..40e78e83 100644
--- a/exchange/bidder.go
+++ b/exchange/bidder.go
@@ -140,7 +140,7 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, request *openrtb2.B
 		}
 		return nil, errs
 	}
-	xPrebidHeader := buildXPrebidHeader(request, version.Ver)
+	xPrebidHeader := version.BuildXPrebidHeaderForRequest(request, version.Ver)
 
 	for i := 0; i < len(reqData); i++ {
 		if reqData[i].Headers != nil {
diff --git a/exchange/utils.go b/exchange/utils.go
index ec5b666d..44737af3 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"math/rand"
-	"strings"
 
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/go-gdpr/vendorconsent"
@@ -713,42 +712,6 @@ func getExtBidAdjustmentFactors(requestExt *openrtb_ext.ExtRequest) map[string]f
 	return bidAdjustmentFactors
 }
 
-func buildXPrebidHeader(bidRequest *openrtb2.BidRequest, version string) string {
-	req := &openrtb_ext.RequestWrapper{BidRequest: bidRequest}
-
-	sb := &strings.Builder{}
-	writeNameVersionRecord(sb, "pbs-go", version)
-
-	if reqExt, err := req.GetRequestExt(); err == nil && reqExt != nil {
-		if prebidExt := reqExt.GetPrebid(); prebidExt != nil {
-			if channel := prebidExt.Channel; channel != nil {
-				writeNameVersionRecord(sb, channel.Name, channel.Version)
-			}
-		}
-	}
-	if appExt, err := req.GetAppExt(); err == nil && appExt != nil {
-		if prebidExt := appExt.GetPrebid(); prebidExt != nil {
-			writeNameVersionRecord(sb, prebidExt.Source, prebidExt.Version)
-		}
-	}
-	return sb.String()
-}
-
-func writeNameVersionRecord(sb *strings.Builder, name, version string) {
-	if name == "" {
-		return
-	}
-	if version == "" {
-		version = "unknown"
-	}
-	if sb.Len() != 0 {
-		sb.WriteString(",")
-	}
-	sb.WriteString(name)
-	sb.WriteString("/")
-	sb.WriteString(version)
-}
-
 func applyFPD(fpd *firstpartydata.ResolvedFirstPartyData, bidReq *openrtb2.BidRequest) {
 	if fpd.Site != nil {
 		bidReq.Site = fpd.Site
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 941f1a56..7cb7a07b 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -79,7 +79,6 @@ const (
 	Bidder33Across          BidderName = "33across"
 	BidderAceex             BidderName = "aceex"
 	BidderAcuityAds         BidderName = "acuityads"
-	BidderAdagio            BidderName = "adagio"
 	BidderAdf               BidderName = "adf"
 	BidderAdform            BidderName = "adform"
 	BidderAdgeneration      BidderName = "adgeneration"
@@ -207,6 +206,7 @@ const (
 	BidderValueImpression   BidderName = "valueimpression"
 	BidderVerizonMedia      BidderName = "verizonmedia"
 	BidderVideoByte         BidderName = "videobyte"
+	BidderVidoomy           BidderName = "vidoomy"
 	BidderVisx              BidderName = "visx"
 	BidderViewdeos          BidderName = "viewdeos"
 	BidderVrtcal            BidderName = "vrtcal"
@@ -225,7 +225,6 @@ func CoreBidderNames() []BidderName {
 		Bidder33Across,
 		BidderAceex,
 		BidderAcuityAds,
-		BidderAdagio,
 		BidderAdf,
 		BidderAdform,
 		BidderAdgeneration,
@@ -353,6 +352,7 @@ func CoreBidderNames() []BidderName {
 		BidderValueImpression,
 		BidderVerizonMedia,
 		BidderVideoByte,
+		BidderVidoomy,
 		BidderViewdeos,
 		BidderVisx,
 		BidderVrtcal,
diff --git a/openrtb_ext/imp_vidoomy.go b/openrtb_ext/imp_vidoomy.go
new file mode 100644
index 00000000..21072dae
--- /dev/null
+++ b/openrtb_ext/imp_vidoomy.go
@@ -0,0 +1,5 @@
+package openrtb_ext
+
+type ImpExtVidoomy struct {
+	ZoneID string `json:"zoneId"`
+}
diff --git a/static/bidder-info/adagio.yaml b/static/bidder-info/adagio.yaml
deleted file mode 100644
index 891b2a6c..00000000
--- a/static/bidder-info/adagio.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-maintainer:
-  email: "dev@adagio.io"
-gvlVendorID: 617
-modifyingVastXmlAllowed: false
-debug:
-  allow: true
-capabilities:
-  site:
-    mediaTypes:
-      - banner
-      - video
-      - native
-userSync:
-  redirect:
-    url: "https://mp.4dex.io/sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}"
-    userMacro: "{{UID}}"
diff --git a/static/bidder-info/vidoomy.yaml b/static/bidder-info/vidoomy.yaml
new file mode 100644
index 00000000..1cd683a7
--- /dev/null
+++ b/static/bidder-info/vidoomy.yaml
@@ -0,0 +1,16 @@
+maintainer:
+  email: support@vidoomy.com
+gvlVendorID: 380
+capabilities:
+  site:
+    mediaTypes:
+      - banner
+      - video
+  app:
+    mediaTypes:
+      - banner
+      - video
+userSync:
+    iframe:
+      url: "https://vid.vidoomy.com/sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}"
+      userMacro: "{{VID}}"
\ No newline at end of file
diff --git a/static/bidder-params/adagio.json b/static/bidder-params/adagio.json
deleted file mode 100644
index 955c58c7..00000000
--- a/static/bidder-params/adagio.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-04/schema#",
-  "title": "Adagio Adapter Params",
-  "description": "A schema which validates params accepted by the Adagio adapter",
-  "type": "object",
-  "required": [
-    "organizationId",
-    "site",
-    "placement"
-  ],
-  "properties": {
-    "organizationId": {
-      "type": "string",
-      "description": "Name to identify the organization",
-      "minLength": 1
-    },
-    "site": {
-      "type": "string",
-      "description": "Name to identify the site",
-      "minLength": 1
-    },
-    "placement": {
-      "type": "string",
-      "description": "Name to identify the placement",
-      "minLength": 1
-    },
-    "pageviewId": {
-      "type": "string",
-      "description": "Name to identify the pageview"
-    },
-    "pagetype": {
-      "type": "string",
-      "description": "Name to identify the page type"
-    },
-    "category": {
-      "type": "string",
-      "description": "Name to identify the category"
-    },
-    "subcategory": {
-      "type": "string",
-      "description": "Name to identify the subcategory"
-    },
-    "environment": {
-      "type": "string",
-      "description": "Name to identify the environment"
-    },
-    "features": {
-      "type": "object",
-      "patternProperties": {
-        "^[a-zA-Z_]": { "type": "string" }
-      }
-    },
-    "prebidVersion:": {
-      "type": "string",
-      "description": "Name to identify the version of Prebid.js"
-    },
-    "debug": {
-      "type": "object",
-      "properties": {
-        "enabled": {
-          "type": "boolean"
-        },
-        "cpm": {
-          "type": "number"
-        },
-        "lazyLoad": {
-          "type": "object",
-          "properties": {
-            "enabled": {
-              "type": "boolean"
-            },
-            "threshold": {
-              "type": "number"
-            },
-            "rootMargin":  {
-              "type": "string"
-            }
-          }
-        }
-      }
-    },
-    "native": {
-      "type": "object",
-      "properties": {
-        "context": {
-          "type": "number"
-        },
-        "plcmttype": {
-          "type": "number"
-        }
-      }
-    }
-  }
-}
diff --git a/static/bidder-params/vidoomy.json b/static/bidder-params/vidoomy.json
new file mode 100644
index 00000000..9c49daf7
--- /dev/null
+++ b/static/bidder-params/vidoomy.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Vidoomy Adapter Params",
+  "description": "A schema which validates params accepted by the Vidoomy adapter",
+  "type": "object",
+  "properties": {
+    "zoneId": {
+      "type": "string",
+      "description": "Specific zone ID for this placement, belonging to app/site",
+      "minLength": 1
+    }
+  },
+  "required": ["zoneId"]
+}
\ No newline at end of file
diff --git a/version/version.go b/version/version.go
index e9310276..4292abbe 100644
--- a/version/version.go
+++ b/version/version.go
@@ -6,6 +6,9 @@ package version
 // Populated automatically at build / releases in the Docker image
 var Ver string
 
+// VerUnknown is the version used if Ver has not been set by ldflags.
+const VerUnknown = "unknown"
+
 // Rev holds binary revision string
 // Populated using:
 //    go build -ldflags "-X github.com/prebid/prebid-server/version.Rev=`git rev-parse --short HEAD`"
diff --git a/version/xprebidheader.go b/version/xprebidheader.go
new file mode 100644
index 00000000..5d91ca49
--- /dev/null
+++ b/version/xprebidheader.go
@@ -0,0 +1,53 @@
+package version
+
+import (
+	"strings"
+
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+const xPrebidHeaderVersionPrefix = "pbs-go"
+
+func BuildXPrebidHeader(version string) string {
+	sb := &strings.Builder{}
+	writeNameVersionRecord(sb, xPrebidHeaderVersionPrefix, version)
+	return sb.String()
+}
+
+func BuildXPrebidHeaderForRequest(bidRequest *openrtb2.BidRequest, version string) string {
+	req := &openrtb_ext.RequestWrapper{BidRequest: bidRequest}
+
+	sb := &strings.Builder{}
+	writeNameVersionRecord(sb, xPrebidHeaderVersionPrefix, version)
+
+	if reqExt, err := req.GetRequestExt(); err == nil && reqExt != nil {
+		if prebidExt := reqExt.GetPrebid(); prebidExt != nil {
+			if channel := prebidExt.Channel; channel != nil {
+				writeNameVersionRecord(sb, channel.Name, channel.Version)
+			}
+		}
+	}
+	if appExt, err := req.GetAppExt(); err == nil && appExt != nil {
+		if prebidExt := appExt.GetPrebid(); prebidExt != nil {
+			writeNameVersionRecord(sb, prebidExt.Source, prebidExt.Version)
+		}
+	}
+	return sb.String()
+}
+
+func writeNameVersionRecord(sb *strings.Builder, name, version string) {
+	if name == "" {
+		return
+	}
+	if version == "" {
+		version = VerUnknown
+	}
+	if sb.Len() != 0 {
+		sb.WriteString(",")
+	}
+	sb.WriteString(name)
+	sb.WriteString("/")
+	sb.WriteString(version)
+}


Test patch:
diff --git a/adapters/adagio/adagio_test.go b/adapters/adagio/adagio_test.go
deleted file mode 100644
index d5e25c78..00000000
--- a/adapters/adagio/adagio_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package adagio
-
-import (
-	"encoding/json"
-	"github.com/mxmCherry/openrtb/v15/openrtb2"
-	"github.com/stretchr/testify/assert"
-	"testing"
-
-	"github.com/prebid/prebid-server/adapters/adapterstest"
-	"github.com/prebid/prebid-server/config"
-	"github.com/prebid/prebid-server/openrtb_ext"
-)
-
-func buildFakeBidRequest() openrtb2.BidRequest {
-	imp1 := openrtb2.Imp{
-		ID:     "some-impression-id",
-		Banner: &openrtb2.Banner{},
-		Ext:    json.RawMessage(`{"bidder": {"organizationId": "1000", "site": "site-name", "placement": "ban_atf"}}`),
-	}
-
-	fakeBidRequest := openrtb2.BidRequest{
-		ID:  "some-request-id",
-		Imp: []openrtb2.Imp{imp1},
-	}
-
-	return fakeBidRequest
-}
-
-func TestJsonSamples(t *testing.T) {
-	bidder, buildErr := Builder(openrtb_ext.BidderAdagio, config.Adapter{
-		Endpoint: "http://localhost/prebid_server"})
-
-	if buildErr != nil {
-		t.Fatalf("Builder returned unexpected error %v", buildErr)
-	}
-
-	adapterstest.RunJSONBidderTest(t, "adagiotest", bidder)
-}
-
-func TestMakeRequests_NoGzip(t *testing.T) {
-	fakeBidRequest := buildFakeBidRequest()
-	fakeBidRequest.Test = 1 // Do not use Gzip in Test Mode.
-
-	bidder, buildErr := Builder(openrtb_ext.BidderAdagio, config.Adapter{
-		Endpoint: "http://localhost/prebid_server"})
-
-	if buildErr != nil {
-		t.Fatalf("Builder returned unexpected error %v", buildErr)
-	}
-
-	requestData, errs := bidder.MakeRequests(&fakeBidRequest, nil)
-
-	assert.Nil(t, errs)
-	assert.Equal(t, 1, len(requestData))
-
-	body := &openrtb2.BidRequest{}
-	err := json.Unmarshal(requestData[0].Body, body)
-	assert.NoError(t, err, "Request body unmarshalling error should be nil")
-	assert.Equal(t, 1, len(body.Imp))
-}
-
-func TestMakeRequests_Gzip(t *testing.T) {
-	fakeBidRequest := buildFakeBidRequest()
-
-	bidder, buildErr := Builder(openrtb_ext.BidderAdagio, config.Adapter{
-		Endpoint: "http://localhost/prebid_server"})
-
-	if buildErr != nil {
-		t.Fatalf("Builder returned unexpected error %v", buildErr)
-	}
-
-	requestData, errs := bidder.MakeRequests(&fakeBidRequest, nil)
-	assert.Empty(t, errs, "Got errors while making requests")
-	assert.Equal(t, []string{"gzip"}, requestData[0].Headers["Content-Encoding"])
-}
diff --git a/adapters/adagio/adagiotest/exemplary/banner-web.json b/adapters/adagio/adagiotest/exemplary/banner-web.json
deleted file mode 100644
index 732b40d2..00000000
--- a/adapters/adagio/adagiotest/exemplary/banner-web.json
+++ /dev/null
@@ -1,155 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "device": {
-      "ua": "test-user-agent",
-      "ip": "123.123.123.123",
-      "language": "en",
-      "dnt": 0
-    },
-    "tmax": 1000,
-    "user": {
-      "buyeruid": "awesome-user"
-    },
-    "site": {
-      "page": "test.com",
-      "publisher": {
-        "id": "123456789"
-      }
-    },
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w":320,
-          "h":50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ],
-          "X-Forwarded-For": [
-            "123.123.123.123"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "device": {
-            "ua": "test-user-agent",
-            "ip": "123.123.123.123",
-            "language": "en",
-            "dnt": 0
-          },
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w":320,
-                "h":50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ],
-          "site": {
-            "page": "test.com",
-            "publisher": {
-              "id": "123456789"
-            }
-          },
-          "user": {
-            "buyeruid": "awesome-user"
-          },
-          "tmax": 1000
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "awesome-resp-id",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-                  "impid": "some-impression-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "w": 320,
-                  "h": 50,
-                  "ext": {
-                    "prebid": {
-                      "type": "banner"
-                    }
-                  }
-                }
-              ],
-              "seat": "adagio"
-            }
-          ],
-          "cur": "USD",
-          "ext": {
-            "responsetimemillis": {
-              "adagio": 154
-            },
-            "tmaxrequest": 1000
-          }
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids":[
-        {
-          "bid":  {
-            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-            "impid": "some-impression-id",
-            "price": 3.5,
-            "adm": "awesome-markup",
-            "crid": "20",
-            "adomain": [
-              "awesome.com"
-            ],
-            "w": 320,
-            "h": 50,
-            "ext": {
-              "prebid": {
-                "type": "banner"
-              }
-            }
-          },
-          "type": "banner"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/adagio/adagiotest/exemplary/multi-format.json b/adapters/adagio/adagiotest/exemplary/multi-format.json
deleted file mode 100644
index 85e0be26..00000000
--- a/adapters/adagio/adagiotest/exemplary/multi-format.json
+++ /dev/null
@@ -1,165 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "device": {
-      "ua": "test-user-agent",
-      "ip": "123.123.123.123",
-      "language": "en",
-      "dnt": 0
-    },
-    "tmax": 1000,
-    "user": {
-      "buyeruid": "awesome-user"
-    },
-    "site": {
-      "page": "test.com",
-      "publisher": {
-        "id": "123456789"
-      }
-    },
-    "imp": [
-      {
-        "id": "multi-format-id",
-        "banner": {
-          "w":320,
-          "h":50
-        },
-        "video": {
-          "mimes": ["video\/mp4"],
-          "w": 640,
-          "h": 480
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ],
-          "X-Forwarded-For": [
-            "123.123.123.123"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "device": {
-            "ua": "test-user-agent",
-            "ip": "123.123.123.123",
-            "language": "en",
-            "dnt": 0
-          },
-          "imp": [
-            {
-              "id": "multi-format-id",
-              "banner": {
-                "w":320,
-                "h":50
-              },
-              "video": {
-                "mimes": ["video\/mp4"],
-                "w": 640,
-                "h": 480
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ],
-          "site": {
-            "page": "test.com",
-            "publisher": {
-              "id": "123456789"
-            }
-          },
-          "user": {
-            "buyeruid": "awesome-user"
-          },
-          "tmax": 1000
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "awesome-resp-id",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-                  "impid": "multi-format-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "w": 320,
-                  "h": 50,
-                  "ext": {
-                    "prebid": {
-                      "type": "banner"
-                    }
-                  }
-                }
-              ],
-              "seat": "adagio"
-            }
-          ],
-          "cur": "USD",
-          "ext": {
-            "responsetimemillis": {
-              "adagio": 154
-            },
-            "tmaxrequest": 1000
-          }
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids":[
-        {
-          "bid":  {
-            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-            "impid": "multi-format-id",
-            "price": 3.5,
-            "adm": "awesome-markup",
-            "crid": "20",
-            "adomain": [
-              "awesome.com"
-            ],
-            "w": 320,
-            "h": 50,
-            "ext": {
-              "prebid": {
-                "type": "banner"
-              }
-            }
-          },
-          "type": "banner"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/adagio/adagiotest/exemplary/multi-imp.json b/adapters/adagio/adagiotest/exemplary/multi-imp.json
deleted file mode 100644
index 66af28ea..00000000
--- a/adapters/adagio/adagiotest/exemplary/multi-imp.json
+++ /dev/null
@@ -1,222 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "device": {
-      "ua": "test-user-agent",
-      "ip": "123.123.123.123",
-      "language": "en",
-      "dnt": 0
-    },
-    "tmax": 1000,
-    "user": {
-      "buyeruid": "awesome-user"
-    },
-    "site": {
-      "page": "test.com",
-      "publisher": {
-        "id": "123456789"
-      }
-    },
-    "imp": [
-      {
-        "id": "banner-impression-id",
-        "banner": {
-          "w":320,
-          "h":50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      },
-      {
-        "id": "video-impression-id",
-        "video": {
-          "mimes": ["video\/mp4"],
-          "w": 640,
-          "h": 480
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "in_article"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ],
-          "X-Forwarded-For": [
-            "123.123.123.123"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "device": {
-            "ua": "test-user-agent",
-            "ip": "123.123.123.123",
-            "language": "en",
-            "dnt": 0
-          },
-          "imp": [
-            {
-              "id": "banner-impression-id",
-              "banner": {
-                "w":320,
-                "h":50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            },
-            {
-              "id": "video-impression-id",
-              "video": {
-                "mimes": ["video\/mp4"],
-                "w": 640,
-                "h": 480
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "in_article"
-                }
-              }
-            }
-          ],
-          "site": {
-            "page": "test.com",
-            "publisher": {
-              "id": "123456789"
-            }
-          },
-          "user": {
-            "buyeruid": "awesome-user"
-          },
-          "tmax": 1000
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "awesome-resp-id",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-                  "impid": "banner-impression-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "w": 320,
-                  "h": 50,
-                  "ext": {
-                    "prebid": {
-                      "type": "banner"
-                    }
-                  }
-                },
-                {
-                  "id": "b4ae1b4e2fc24a4fb45540082e98e162",
-                  "impid": "video-impression-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "w": 640,
-                  "h": 480,
-                  "ext": {
-                    "prebid": {
-                      "type": "video"
-                    }
-                  }
-                }
-              ],
-              "seat": "adagio"
-            }
-          ],
-          "cur": "USD",
-          "ext": {
-            "responsetimemillis": {
-              "adagio": 154
-            },
-            "tmaxrequest": 1000
-          }
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids":[
-        {
-          "bid":  {
-            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-            "impid": "banner-impression-id",
-            "price": 3.5,
-            "adm": "awesome-markup",
-            "crid": "20",
-            "adomain": [
-              "awesome.com"
-            ],
-            "w": 320,
-            "h": 50,
-            "ext": {
-              "prebid": {
-                "type": "banner"
-              }
-            }
-          },
-          "type": "banner"
-        },
-        {
-          "bid":  {
-            "id": "b4ae1b4e2fc24a4fb45540082e98e162",
-            "impid": "video-impression-id",
-            "price": 3.5,
-            "adm": "awesome-markup",
-            "crid": "20",
-            "adomain": [
-              "awesome.com"
-            ],
-            "w": 640,
-            "h": 480,
-            "ext": {
-              "prebid": {
-                "type": "video"
-              }
-            }
-          },
-          "type": "video"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/adagio/adagiotest/exemplary/native-web.json b/adapters/adagio/adagiotest/exemplary/native-web.json
deleted file mode 100644
index 0085aadd..00000000
--- a/adapters/adagio/adagiotest/exemplary/native-web.json
+++ /dev/null
@@ -1,151 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "device": {
-      "ua": "test-user-agent",
-      "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
-      "language": "en",
-      "dnt": 0
-    },
-    "tmax": 1000,
-    "user": {
-      "buyeruid": "awesome-user"
-    },
-    "site": {
-      "page": "test.com",
-      "publisher": {
-        "id": "123456789"
-      }
-    },
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "native": {
-          "ver":"1.1",
-          "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "in_article"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ],
-          "X-Forwarded-For": [
-            "2607:fb90:f27:4512:d800:cb23:a603:e245"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "device": {
-            "ua": "test-user-agent",
-            "ipv6": "2607:fb90:f27:4512:d800:cb23:a603:e245",
-            "language": "en",
-            "dnt": 0
-          },
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "native": {
-                "ver":"1.1",
-                "request":"{\"adunit\":2,\"assets\":[{\"id\":3,\"img\":{\"h\":120,\"hmin\":0,\"type\":3,\"w\":180,\"wmin\":0},\"required\":1},{\"id\":0,\"required\":1,\"title\":{\"len\":25}},{\"data\":{\"len\":25,\"type\":1},\"id\":4,\"required\":1},{\"data\":{\"len\":140,\"type\":2},\"id\":6,\"required\":1}],\"context\":1,\"layout\":1,\"contextsubtype\":11,\"plcmtcnt\":1,\"plcmttype\":2,\"ver\":\"1.1\",\"ext\":{\"banner\":{\"w\":320,\"h\":50}}}"
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "in_article"
-                }
-              }
-            }
-          ],
-          "site": {
-            "page": "test.com",
-            "publisher": {
-              "id": "123456789"
-            }
-          },
-          "user": {
-            "buyeruid": "awesome-user"
-          },
-          "tmax": 1000
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "awesome-resp-id",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-                  "impid": "some-impression-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "ext": {
-                    "prebid": {
-                      "type": "native"
-                    }
-                  }
-                }
-              ],
-              "seat": "adagio"
-            }
-          ],
-          "cur": "USD",
-          "ext": {
-            "responsetimemillis": {
-              "acuityads": 154
-            },
-            "tmaxrequest": 1000
-          }
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids":[
-        {
-          "bid":  {
-            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-            "impid": "some-impression-id",
-            "price": 3.5,
-            "adm": "awesome-markup",
-            "crid": "20",
-            "adomain": [
-              "awesome.com"
-            ],
-            "ext": {
-              "prebid": {
-                "type": "native"
-              }
-            }
-          },
-          "type": "native"
-        }
-      ]
-    }
-  ]
-}
diff --git a/adapters/adagio/adagiotest/exemplary/video-web.json b/adapters/adagio/adagiotest/exemplary/video-web.json
deleted file mode 100644
index 353420ee..00000000
--- a/adapters/adagio/adagiotest/exemplary/video-web.json
+++ /dev/null
@@ -1,175 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "device": {
-      "ua": "test-user-agent",
-      "ip": "123.123.123.123",
-      "language": "en",
-      "dnt": 0
-    },
-    "tmax": 1000,
-    "user": {
-      "buyeruid": "awesome-user"
-    },
-    "site": {
-      "page": "test.com",
-      "publisher": {
-        "id": "123456789"
-      }
-    },
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "video": {
-          "mimes": [
-            "video\/mp4"
-          ],
-          "w": 640,
-          "h": 480,
-          "minduration": 120,
-          "maxduration": 150
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "in_article"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ],
-          "X-Forwarded-For": [
-            "123.123.123.123"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "device": {
-            "ua": "test-user-agent",
-            "ip": "123.123.123.123",
-            "language": "en",
-            "dnt": 0
-          },
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "video": {
-                "mimes": [
-                  "video\/mp4"
-                ],
-                "minduration": 120,
-                "maxduration": 150,
-                "w": 640,
-                "h": 480
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "in_article"
-                }
-              }
-            }
-          ],
-          "site": {
-            "page": "test.com",
-            "publisher": {
-              "id": "123456789"
-            }
-          },
-          "user": {
-            "buyeruid": "awesome-user"
-          },
-          "tmax": 1000
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "awesome-resp-id",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-                  "impid": "some-impression-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "w": 1280,
-                  "h": 720,
-                  "ext": {
-                    "adagio": {
-                      "outstream": {
-                        "bvwUrl": "https://cool.io"
-                      }
-                    },
-                    "prebid": {
-                      "type": "video"
-                    }
-                  }
-                }
-              ],
-              "seat": "adagio"
-            }
-          ],
-          "cur": "USD",
-          "ext": {
-            "responsetimemillis": {
-              "adagio": 154
-            },
-            "tmaxrequest": 1000
-          }
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": [
-        {
-          "bid": {
-            "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-            "impid": "some-impression-id",
-            "price": 3.5,
-            "adm": "awesome-markup",
-            "adomain": [
-              "awesome.com"
-            ],
-            "crid": "20",
-            "w": 1280,
-            "h": 720,
-            "ext": {
-              "adagio": {
-                "outstream": {
-                  "bvwUrl": "https://cool.io"
-                }
-              },
-              "prebid": {
-                "type": "video"
-              }
-            }
-          },
-          "type":"video"
-        }
-      ]
-    }
-  ]
-}
\ No newline at end of file
diff --git a/adapters/adagio/adagiotest/supplemental/response-miss-ext-bid-type.json b/adapters/adagio/adagiotest/supplemental/response-miss-ext-bid-type.json
deleted file mode 100644
index 7b1267f6..00000000
--- a/adapters/adagio/adagiotest/supplemental/response-miss-ext-bid-type.json
+++ /dev/null
@@ -1,130 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "device": {
-      "ua": "test-user-agent",
-      "ip": "123.123.123.123",
-      "language": "en",
-      "dnt": 0
-    },
-    "tmax": 1000,
-    "user": {
-      "buyeruid": "awesome-user"
-    },
-    "site": {
-      "page": "test.com",
-      "publisher": {
-        "id": "123456789"
-      }
-    },
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ],
-          "X-Forwarded-For": [
-            "123.123.123.123"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "device": {
-            "ua": "test-user-agent",
-            "ip": "123.123.123.123",
-            "language": "en",
-            "dnt": 0
-          },
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ],
-          "site": {
-            "page": "test.com",
-            "publisher": {
-              "id": "123456789"
-            }
-          },
-          "user": {
-            "buyeruid": "awesome-user"
-          },
-          "tmax": 1000
-        }
-      },
-      "mockResponse": {
-        "status": 200,
-        "body": {
-          "id": "awesome-resp-id",
-          "seatbid": [
-            {
-              "bid": [
-                {
-                  "id": "a3ae1b4e2fc24a4fb45540082e98e161",
-                  "impid": "some-impression-id",
-                  "price": 3.5,
-                  "adm": "awesome-markup",
-                  "adomain": [
-                    "awesome.com"
-                  ],
-                  "crid": "20",
-                  "w": 320,
-                  "h": 50,
-                  "ext": {}
-                }
-              ],
-              "seat": "adagio"
-            }
-          ],
-          "cur": "USD",
-          "ext": {
-            "responsetimemillis": {
-              "adagio": 154
-            },
-            "tmaxrequest": 1000
-          }
-        }
-      }
-    }
-  ],
-  "expectedBidResponses": [
-    {
-      "bids": []
-    }
-  ]
-}
diff --git a/adapters/adagio/adagiotest/supplemental/status-204.json b/adapters/adagio/adagiotest/supplemental/status-204.json
deleted file mode 100644
index 4d604a01..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-204.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 204,
-        "body": {}
-      }
-    }
-  ],
-  "expectedBidResponses": []
-}
diff --git a/adapters/adagio/adagiotest/supplemental/status-400.json b/adapters/adagio/adagiotest/supplemental/status-400.json
deleted file mode 100644
index 093c5458..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-400.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 400,
-        "body": "bad request"
-      }
-    }
-  ],
-  "expectedMakeBidsErrors": [
-    {
-      "value": "Unexpected status code: 400. Run with request.debug = 1 for more info",
-      "comparison": "literal"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/adapters/adagio/adagiotest/supplemental/status-401.json b/adapters/adagio/adagiotest/supplemental/status-401.json
deleted file mode 100644
index a33aca20..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-401.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 401,
-        "body": "unauthorized"
-      }
-    }
-  ],
-  "expectedMakeBidsErrors": [
-    {
-      "value": "Unexpected status code: 401. Run with request.debug = 1 for more info",
-      "comparison": "literal"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/adapters/adagio/adagiotest/supplemental/status-403.json b/adapters/adagio/adagiotest/supplemental/status-403.json
deleted file mode 100644
index 59c5a9cb..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-403.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 403,
-        "body": "forbidden"
-      }
-    }
-  ],
-  "expectedMakeBidsErrors": [
-    {
-      "value": "Unexpected status code: 403. Run with request.debug = 1 for more info",
-      "comparison": "literal"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/adapters/adagio/adagiotest/supplemental/status-500.json b/adapters/adagio/adagiotest/supplemental/status-500.json
deleted file mode 100644
index 0077d745..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-500.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "debug": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 500,
-        "body": "internal error"
-      }
-    }
-  ],
-  "expectedMakeBidsErrors": [
-    {
-      "value": "Unexpected status code: 500. Run with request.debug = 1 for more info",
-      "comparison": "literal"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/adapters/adagio/adagiotest/supplemental/status-503.json b/adapters/adagio/adagiotest/supplemental/status-503.json
deleted file mode 100644
index d2a52893..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-503.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 503,
-        "body": "Service unavailable"
-      }
-    }
-  ],
-  "expectedMakeBidsErrors": [
-    {
-      "value": "Unexpected status code: 503. Run with request.debug = 1 for more info",
-      "comparison": "literal"
-    }
-  ]
-}
diff --git a/adapters/adagio/adagiotest/supplemental/status-504.json b/adapters/adagio/adagiotest/supplemental/status-504.json
deleted file mode 100644
index 1b779d5c..00000000
--- a/adapters/adagio/adagiotest/supplemental/status-504.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "mockBidRequest": {
-    "test": 1,
-    "id": "some-request-id",
-    "imp": [
-      {
-        "id": "some-impression-id",
-        "banner": {
-          "w": 320,
-          "h": 50
-        },
-        "ext": {
-          "bidder": {
-            "organizationId": "1000",
-            "site": "site-name",
-            "placement": "ban_atf"
-          }
-        }
-      }
-    ]
-  },
-  "httpCalls": [
-    {
-      "expectedRequest": {
-        "headers": {
-          "Content-Type": [
-            "application/json;charset=utf-8"
-          ],
-          "Accept": [
-            "application/json"
-          ]
-        },
-        "uri": "http://localhost/prebid_server",
-        "body": {
-          "test": 1,
-          "id": "some-request-id",
-          "imp": [
-            {
-              "id": "some-impression-id",
-              "banner": {
-                "w": 320,
-                "h": 50
-              },
-              "ext": {
-                "bidder": {
-                  "organizationId": "1000",
-                  "site": "site-name",
-                  "placement": "ban_atf"
-                }
-              }
-            }
-          ]
-        }
-      },
-      "mockResponse": {
-        "status": 504,
-        "body": "gateway timeout"
-      }
-    }
-  ],
-  "expectedMakeBidsErrors": [
-    {
-      "value": "Unexpected status code: 504. Run with request.debug = 1 for more info",
-      "comparison": "literal"
-    }
-  ]
-}
\ No newline at end of file
diff --git a/adapters/adagio/params_test.go b/adapters/adagio/params_test.go
deleted file mode 100644
index ee8f702e..00000000
--- a/adapters/adagio/params_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package adagio
-
-import (
-	"encoding/json"
-	"testing"
-
-	"github.com/prebid/prebid-server/openrtb_ext"
-)
-
-var validParams = []string{
-	`{ "organizationId": "1234", "site": "adagio-io", "placement": "ban_atf" }`,
-	`{ "organizationId": "1234", "site": "adagio-io", "placement": "ban_atf", "_unknown": "ban_atf"}`,
-	`{ "organizationId": "1234", "site": "adagio-io", "placement": "ban_atf", "features": {"a": "a", "b": "b"}}`,
-}
-
-func TestValidParams(t *testing.T) {
-	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
-	if err != nil {
-		t.Fatalf("Failed to fetch the json-schemas. %v", err)
-	}
-
-	for _, validParam := range validParams {
-		if err := validator.Validate(openrtb_ext.BidderAdagio, json.RawMessage(validParam)); err != nil {
-			t.Errorf("Schema rejected Adagio params: %s", validParam)
-		}
-	}
-}
-
-var invalidParams = []string{
-	``,
-	`null`,
-	`true`,
-	`5`,
-	`4.2`,
-	`[]`,
-	`{}`,
-	`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
-	`{ "organizationId": "", "site": "", "placement": "" }`,
-	`{ "organizationId": "", "site": "2", "placement": "3" }`,
-	`{ "organizationId": "1", "site": "", "placement": "3" }`,
-	`{ "organizationId": "1", "site": "2", "placement": "" }`,
-	`{ "organizationId": 1, "site": "2", "placement": "3" }`,
-	`{ "organizationId": "1234", "site": "adagio-io", "placement": "ban_atf", "features": {"a": "a", "notastring": true}}`,
-}
-
-func TestInvalidParams(t *testing.T) {
-	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
-	if err != nil {
-		t.Fatalf("Failed to fetch the json-schemas. %v", err)
-	}
-
-	for _, invalidParam := range invalidParams {
-		if err := validator.Validate(openrtb_ext.BidderAdagio, json.RawMessage(invalidParam)); err == nil {
-			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
-		}
-	}
-}
diff --git a/adapters/algorix/algorixtest/exemplary/sample-banner-with-mediatype.json b/adapters/algorix/algorixtest/exemplary/sample-banner-with-mediatype.json
new file mode 100644
index 00000000..c9f9f877
--- /dev/null
+++ b/adapters/algorix/algorixtest/exemplary/sample-banner-with-mediatype.json
@@ -0,0 +1,105 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 320, "h": 50}]
+        },
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 320,
+          "h": 480
+        },
+        "ext": {
+          "bidder": {
+            "sid": "testSid",
+            "token": "testToken",
+            "region": "APAC"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://apac.xyz.test.com?sid=testSid&token=testToken",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "banner": {
+                "format": [{"w": 320, "h": 50}],
+                "w": 320,
+                "h": 50
+              },
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 320,
+                "h": 480
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "testSid",
+                  "token": "testToken",
+                  "region": "APAC"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "ttx",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.5,
+                "adm": "some-ads",
+                "crid": "crid_testid",
+                "ext": {
+                  "mediaType": "video"
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-ads",
+            "crid": "crid_testid",
+            "ext": {
+              "mediaType": "video"
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/algorix/algorixtest/exemplary/sample-rewarded-video.json b/adapters/algorix/algorixtest/exemplary/sample-rewarded-video.json
new file mode 100644
index 00000000..0d98de60
--- /dev/null
+++ b/adapters/algorix/algorixtest/exemplary/sample-rewarded-video.json
@@ -0,0 +1,102 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "w": 320,
+          "h": 480,
+          "mimes": [
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "testSid",
+            "token": "testToken",
+            "placementId": "testPlacementId",
+            "appId": "testAppId"
+          },
+          "prebid": {
+            "is_rewarded_inventory": 1
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://xyz.test.com?sid=testSid&token=testToken",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "video": {
+                "w": 320,
+                "h": 480,
+                "mimes": [
+                  "video/mp4"
+                ],
+                "ext": {
+                  "rewarded": 1
+                }
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "testSid",
+                  "token": "testToken",
+                  "placementId": "testPlacementId",
+                  "appId": "testAppId"
+                },
+                "prebid": {
+                  "is_rewarded_inventory": 1
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "ttx",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 1.2,
+                "adm": "some-ads",
+                "crid": "crid_testid"
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 1.2,
+            "adm": "some-ads",
+            "crid": "crid_testid"
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/algorix/algorixtest/supplemental/multiformat-no-mediatype-response.json b/adapters/algorix/algorixtest/supplemental/multiformat-no-mediatype-response.json
new file mode 100644
index 00000000..3828c52d
--- /dev/null
+++ b/adapters/algorix/algorixtest/supplemental/multiformat-no-mediatype-response.json
@@ -0,0 +1,90 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": [
+            "video/mp4"
+          ],
+          "w": 320,
+          "h": 480
+        },
+        "banner": {
+          "format": [{"w": 320, "h": 50}]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "testSid",
+            "token": "testToken",
+            "region": "APAC"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://apac.xyz.test.com?sid=testSid&token=testToken",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "banner": {
+                "format": [{"w": 320, "h": 50}],
+                "w": 320,
+                "h": 50
+              },
+              "video": {
+                "mimes": [
+                  "video/mp4"
+                ],
+                "w": 320,
+                "h": 480
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "testSid",
+                  "token": "testToken",
+                  "region": "APAC"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "ttx",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.5,
+                "adm": "some-ads",
+                "crid": "crid_testid",
+                "ext": {
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "comparison": "literal",
+      "value": "unable to fetch mediaType in multi-format: test-imp-id"
+    }
+  ]
+}
diff --git a/adapters/algorix/algorixtest/supplemental/sample-banner-with-other-mediatype.json b/adapters/algorix/algorixtest/supplemental/sample-banner-with-other-mediatype.json
new file mode 100644
index 00000000..df535318
--- /dev/null
+++ b/adapters/algorix/algorixtest/supplemental/sample-banner-with-other-mediatype.json
@@ -0,0 +1,91 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 320, "h": 50}]
+        },
+        "ext": {
+          "bidder": {
+            "sid": "testSid",
+            "token": "testToken",
+            "region": "APAC"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://apac.xyz.test.com?sid=testSid&token=testToken",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id":"test-imp-id",
+              "banner": {
+                "format": [{"w": 320, "h": 50}],
+                "w": 320,
+                "h": 50
+              },
+              "ext": {
+                "bidder": {
+                  "sid": "testSid",
+                  "token": "testToken",
+                  "region": "APAC"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "ttx",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.5,
+                "adm": "some-ads",
+                "crid": "crid_testid",
+                "ext": {
+                  "mediaType": "video"
+                }
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-ads",
+            "crid": "crid_testid",
+            "ext": {
+              "mediaType": "video"
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/huaweiads/huaweiads_test.go b/adapters/huaweiads/huaweiads_test.go
index 03b25d17..d3eeedff 100644
--- a/adapters/huaweiads/huaweiads_test.go
+++ b/adapters/huaweiads/huaweiads_test.go
@@ -4,15 +4,156 @@ import (
 	"github.com/prebid/prebid-server/adapters/adapterstest"
 	"github.com/prebid/prebid-server/config"
 	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
 	"testing"
 )
 
 func TestJsonSamples(t *testing.T) {
 	bidder, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
-		Endpoint: "https://huaweiads.com/adxtest/"})
+		Endpoint: "https://huaweiads.com/adxtest/",
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"com.example.pkgname1\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"p3\",\"p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example1\",\"com.example2\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}," +
+			"{\"convertedPkgName\":\"com.example.pkgname2\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p9\",\"com.example.p10\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"p11\",\"p12\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example3\",\"com.example4\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p15\",\"com.example3.unchanged\"]}]}",
+	})
 
 	if buildErr != nil {
 		t.Fatalf("Builder returned unexpected error %v", buildErr)
 	}
 	adapterstest.RunJSONBidderTest(t, "huaweiadstest", bidder)
 }
+
+func TestExtraInfoDefaultWhenEmpty(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint:         `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: ``,
+	})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	bidderHuaweiAds, _ := bidder.(*adapter)
+
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert, []pkgNameConvert(nil))
+}
+
+func TestExtraInfo1(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint: `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"com.example.pkgname\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p3\",\"com.example.p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p5\",\"com.example.p6\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}]}",
+	})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	bidderHuaweiAds, _ := bidder.(*adapter)
+
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].ConvertedPkgName, "com.example.pkgname")
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].UnconvertedPkgNameKeyWords, []string{"com.example.p3", "com.example.p4"})
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].UnconvertedPkgNamePrefixs, []string{"com.example.p5", "com.example.p6"})
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].UnconvertedPkgNames, []string{"com.example.p1", "com.example.p2"})
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].ExceptionPkgNames, []string{"com.example.p7", "com.example.p8"})
+}
+
+func TestExtraInfo2(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint: `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"com.example.pkgname1\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p3\",\"com.example.p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p5\",\"com.example.p6\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}," +
+			"{\"convertedPkgName\":\"com.example.pkgname2\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p9\",\"com.example.p10\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p11\",\"com.example.p12\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p13\",\"com.example.p14\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p15\",\"com.example.p16\"]}]}",
+	})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	bidderHuaweiAds, _ := bidder.(*adapter)
+
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[1].ConvertedPkgName, "com.example.pkgname2")
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].UnconvertedPkgNameKeyWords, []string{"com.example.p3", "com.example.p4"})
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[1].UnconvertedPkgNamePrefixs, []string{"com.example.p13", "com.example.p14"})
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[0].UnconvertedPkgNames, []string{"com.example.p1", "com.example.p2"})
+	assert.Equal(t, bidderHuaweiAds.extraInfo.PkgNameConvert[1].ExceptionPkgNames, []string{"com.example.p15", "com.example.p16"})
+}
+
+func TestExtraInfo3(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint: `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p3\",\"com.example.p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p5\",\"com.example.p6\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}]," +
+			"\"closeSiteSelectionByCountry\":\"1\"}",
+	})
+	assert.Equal(t, buildErr.Error(), "invalid extra info: ConvertedPkgName is empty, pls check")
+}
+
+func TestExtraInfo4(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint: `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"com.example.pkgname1\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"\",\"com.example.p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p5\",\"\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}]," +
+			"\"closeSiteSelectionByCountry\":\"1\"}",
+	})
+	assert.Equal(t, buildErr.Error(), "invalid extra info: UnconvertedPkgNameKeyWords has a empty keyword, pls check")
+}
+
+func TestExtraInfo5(t *testing.T) {
+	_, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint: `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"com.example.pkgname1\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p3\",\"com.example.p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p5\",\"\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}]," +
+			"\"closeSiteSelectionByCountry\":\"1\"}",
+	})
+	assert.Equal(t, buildErr.Error(), "invalid extra info: UnconvertedPkgNamePrefixs has a empty value, pls check")
+}
+
+func TestExtraInfo6(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderHuaweiAds, config.Adapter{
+		Endpoint: `https://huaweiads.com/adxtest/`,
+		ExtraAdapterInfo: "{\"pkgNameConvert\":[{\"convertedPkgName\":\"com.example.pkgname1\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p1\",\"com.example.p2\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p3\",\"com.example.p4\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p5\",\"com.example.p6\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p7\",\"com.example.p8\"]}," +
+			"{\"convertedPkgName\":\"com.example.pkgname2\"," +
+			"\"unconvertedPkgNames\":[\"com.example.p9\",\"com.example.p10\"]," +
+			"\"unconvertedPkgNameKeyWords\":[\"com.example.p11\",\"com.example.p12\"]," +
+			"\"unconvertedPkgNamePrefixs\":[\"com.example.p13\",\"com.example.p14\"]," +
+			"\"exceptionPkgNames\":[\"com.example.p15\",\"com.example.p16\"]}],\"closeSiteSelectionByCountry\":\"1\"}",
+	})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	bidderHuaweiAds, _ := bidder.(*adapter)
+
+	assert.Equal(t, bidderHuaweiAds.extraInfo.CloseSiteSelectionByCountry, "1")
+}
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner1.json b/adapters/huaweiads/huaweiadstest/exemplary/banner1.json
index 866ff173..df1b40eb 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/banner1.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/banner1.json
@@ -27,7 +27,7 @@
       }
     ],
     "app": {
-      "bundle": "com.wavehk.android",
+      "bundle": "com.example.p1",
       "name": "Huawei Browser",
       "ver": "9.1.0.301",
       "content": {
@@ -38,7 +38,6 @@
       "ua": "useragent",
       "h": 1920,
       "language": "zh",
-      "geoCountry": "CH",
       "model": "COL-TEST",
       "os": "android",
       "osv": "10.0.0",
@@ -75,7 +74,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://acd.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
@@ -95,7 +94,7 @@
             "lang": "zh",
             "country": "CN",
             "name": "Huawei Browser",
-            "pkgname": "com.wavehk.android",
+            "pkgname": "com.example.pkgname1",
             "version": "9.1.0.301"
           },
           "multislot": [
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/banner2.json b/adapters/huaweiads/huaweiadstest/exemplary/banner2.json
index ab3dea21..65580187 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/banner2.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/banner2.json
@@ -55,7 +55,7 @@
       }
     },
     "app": {
-      "bundle": "org.prebid.mobile.prebidjavademo",
+      "bundle": "com.example.p10",
       "ver": "1.11",
       "name": "API1.0Demo",
       "publisher": {
@@ -99,7 +99,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
@@ -119,7 +119,7 @@
             "lang": "en",
             "country": "ZA",
             "name": "API1.0Demo",
-            "pkgname": "org.prebid.mobile.prebidjavademo",
+            "pkgname": "com.example.pkgname2",
             "version": "1.11"
           },
           "multislot": [
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json
new file mode 100644
index 00000000..10fceb5c
--- /dev/null
+++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo1.json
@@ -0,0 +1,253 @@
+{
+  "mockBidRequest": {
+    "id": "test-req-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ],
+          "w": 300,
+          "h": 250
+        },
+        "ext": {
+          "bidder": {
+            "slotid": "m8x9x3rzff",
+            "adtype": "banner",
+            "publisherid": "123",
+            "signkey": "signkey",
+            "keyid": "41",
+            "isTestAuthorization": "true"
+          }
+        }
+      }
+    ],
+    "app": {
+      "bundle": "com.example1.p",
+      "name": "Huawei name",
+      "ver": "9.1.0.301",
+      "content": {
+        "language": "zh"
+      }
+    },
+    "device": {
+      "ua": "useragent",
+      "h": 1920,
+      "language": "en",
+      "model": "COL-TEST",
+      "os": "android",
+      "osv": "10.0.0",
+      "devicetype": 4,
+      "make": "huawei",
+      "w": 1080,
+      "ip": "ip",
+      "pxratio": 23.01,
+      "geo": {
+        "country": "PRT"
+      }
+    },
+    "user": {
+      "ext": {
+        "data": {
+          "gaid": [
+            "gaid"
+          ],
+          "oaid": [
+            "oaid"
+          ],
+          "clientTime": [
+            "2018-11-02 16:34:07.981+1300"
+          ]
+        }
+      }
+    },
+    "regs": {
+      "coppa": 1
+    },
+    "ext": {
+    }
+  },
+  "httpcalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://adx-dre.op.hicloud.com/ppsadx/getResult",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "useragent"
+          ],
+          "Authorization": [
+            "Digest username=123,realm=ppsadx/getResult,nonce=1629473330823,response=d1d61a13a83e1468aa4dff5c8a6cee0b8b381173ca3eb6fa9b313937684d87c0,algorithm=HmacSHA256,usertype=1,keyid=41"
+          ]
+        },
+        "body": {
+          "app": {
+            "lang": "zh",
+            "country": "PT",
+            "name": "Huawei name",
+            "pkgname": "com.example.pkgname1",
+            "version": "9.1.0.301"
+          },
+          "multislot": [
+            {
+              "adtype": 8,
+              "slotid": "m8x9x3rzff",
+              "test": 0,
+              "format": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ],
+              "w": 300,
+              "h": 250
+            }
+          ],
+          "device": {
+            "height": 1920,
+            "language": "en",
+            "oaid": "oaid",
+            "os": "android",
+            "type": 4,
+            "ip": "ip",
+            "localeCountry": "PT",
+            "pxratio": 23.01,
+            "width": 1080,
+            "clientTime": "2018-11-02 16:34:07.981+1300",
+            "gaid": "gaid",
+            "useragent": "useragent",
+            "version": "10.0.0",
+            "maker": "huawei",
+            "model": "COL-TEST",
+            "belongCountry": "PT"
+          },
+          "geo": {
+          },
+          "network": {
+            "type": 0
+          },
+          "regs": {
+            "coppa": 1
+          },
+          "version": "3.4"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "ctrlSwitchs": "0",
+          "dsp1cost": 61,
+          "dspcost": 108,
+          "multiad": [
+            {
+              "adtype": 8,
+              "brsetting": "Y",
+              "content": [
+                {
+                  "clickActionList": [
+                    1
+                  ],
+                  "contentid": "58025103",
+                  "creativetype": 2,
+                  "ctrlSwitchs": "001011001001010112",
+                  "endtime": 1621428898335,
+                  "filterList": [
+                    3
+                  ],
+                  "interactiontype": 1,
+                  "landingTitle": 1,
+                  "metaData": {
+                    "adSign": "2",
+                    "appPromotionChannel": "401721412",
+                    "clickUrl": "https://ads.huawei.com/usermgtportal/home/index.html#/",
+                    "imageInfo": [
+                      {
+                        "checkSha256Flag": 1,
+                        "height": 300,
+                        "imageType": "img",
+                        "sha256": "f5d8487cddaecec45b73fc078649478c80ec646bfec8ed7da4ff931f90eab232",
+                        "url": "https://ads.huawei.com/usermgtportal/home/img/huawei_logo_black.aaec817d.svg",
+                        "width": 250
+                      }
+                    ],
+                    "label": "Banner_API",
+                    "landingPageType": "3"
+                  },
+                  "monitor": [
+                    {
+                      "eventType": "click",
+                      "url": [
+                        "http://test/click1",
+                        "http://test/click2",
+                        "http://test/click3"
+                      ]
+                    },
+                    {
+                      "eventType": "imp",
+                      "url": [
+                        "http://test/imp1",
+                        "http://test/imp2",
+                        "http://test/imp3"
+                      ]
+                    }
+                  ],
+                  "paramfromserver": {
+                    "a": "1||test",
+                    "sig": "",
+                    "t": "99990101235959"
+                  },
+                  "price": 2.8,
+                  "starttime": 1621267200000,
+                  "taskid": "48017658"
+                }
+              ],
+              "retcode30": 200,
+              "slotid": "m8x9x3rzff"
+            }
+          ],
+          "noReportAdTypeEventList": [
+            {
+              "adType": 8,
+              "eventTypeList": [
+                "exception_6"
+              ]
+            }
+          ],
+          "retcode": 200,
+          "totalCacheSize": 300
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<style> html, body  { margin: 0; padding: 0; width: 100%; height: 100%; vertical-align: middle; }  html  { display: table; }  body { display: table-cell; vertical-align: middle; text-align: center; -webkit-text-size-adjust: none; }  </style> <span class=\"title-link advertiser_label\"></span> <a href='https://ads.huawei.com/usermgtportal/home/index.html#/' style=\"text-decoration:none\" onclick=sendGetReq()> <img src='https://ads.huawei.com/usermgtportal/home/img/huawei_logo_black.aaec817d.svg' width='250' height='300'/> </a> <img height=\"1\" width=\"1\" src='http://test/imp1' >  <img height=\"1\" width=\"1\" src='http://test/imp2' >  <img height=\"1\" width=\"1\" src='http://test/imp3' >  <script type=\"text/javascript\">var dspClickTrackings = [\"http://test/click1\",\"http://test/click2\",\"http://test/click3\"];function sendGetReq() {sendSomeGetReq(dspClickTrackings)}function sendOneGetReq(url) {var req = new XMLHttpRequest();req.open('GET', url, true);req.send(null);}function sendSomeGetReq(urls) {for (var i = 0; i < urls.length; i++) {sendOneGetReq(urls[i]);}}</script>",
+            "adomain": [
+              "huaweiads"
+            ],
+            "crid": "58025103",
+            "id": "test-imp-id",
+            "impid": "test-imp-id",
+            "price": 2.8,
+            "h": 300,
+            "w": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json
new file mode 100644
index 00000000..a05ca8d9
--- /dev/null
+++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo2.json
@@ -0,0 +1,271 @@
+{
+  "mockBidRequest": {
+    "id": "a3b18c5b-6708-4bb7-b41b-40ed37d89561",
+    "source": {
+      "tid": "a3b18c5b-6708-4bb7-b41b-40ed37d89561"
+    },
+    "imp": [
+      {
+        "id": "PrebidMobile",
+        "secure": 1,
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ],
+          "api": [
+            5
+          ]
+        },
+        "ext": {
+          "prebid": {
+            "storedrequest": {
+              "id": "1001-1"
+            }
+          },
+          "bidder": {
+            "slotid": "m8x9x3rzff",
+            "adtype": "banner",
+            "publisherid": "123",
+            "signkey": "signkey",
+            "keyid": "41",
+            "isTestAuthorization": "true"
+          }
+        }
+      }
+    ],
+    "device": {
+      "make": "HUAWEI",
+      "model": "LYA-AL00",
+      "ua": "ua",
+      "lmt": 0,
+      "os": "android",
+      "osv": "29",
+      "language": "en",
+      "w": 360,
+      "h": 755,
+      "pxratio": 3,
+      "mccmnc": "424-3",
+      "carrier": "carrier",
+      "connectiontype": 1,
+      "geo": {
+        "country": "RUS"
+      }
+    },
+    "app": {
+      "bundle": "com.example4.p",
+      "ver": "1.11",
+      "name": "API1.0Demo",
+      "publisher": {
+        "id": "1001"
+      },
+      "ext": {
+        "prebid": {
+          "source": "prebid-mobile",
+          "version": "1.11"
+        }
+      }
+    },
+    "user": {
+      "gender": "O",
+      "ext": {
+        "data": {
+          "gaid": [
+            "gaid"
+          ],
+          "oaid": [
+            "oaid"
+          ],
+          "clientTime": [
+            "2018-11-02 16:34:07.981+1300"
+          ]
+        }
+      }
+    },
+    "ext": {
+      "prebid": {
+        "storedrequest": {
+          "id": "1001"
+        },
+        "cache": {
+          "bids": {}
+        },
+        "targeting": {}
+      }
+    }
+  },
+  "httpcalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://adx-drru.op.hicloud.com/ppsadx/getResult",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "ua"
+          ],
+          "Authorization": [
+            "Digest username=123,realm=ppsadx/getResult,nonce=1629473330823,response=d1d61a13a83e1468aa4dff5c8a6cee0b8b381173ca3eb6fa9b313937684d87c0,algorithm=HmacSHA256,usertype=1,keyid=41"
+          ]
+        },
+        "body": {
+          "app": {
+            "lang": "en",
+            "country": "RU",
+            "name": "API1.0Demo",
+            "pkgname": "com.example.pkgname2",
+            "version": "1.11"
+          },
+          "multislot": [
+            {
+              "adtype": 8,
+              "slotid": "m8x9x3rzff",
+              "test": 0,
+              "format": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "device": {
+            "height": 755,
+            "language": "en",
+            "oaid": "oaid",
+            "os": "android",
+            "localeCountry": "RU",
+            "pxratio": 3,
+            "width": 360,
+            "model": "LYA-AL00",
+            "clientTime": "2018-11-02 16:34:07.981+1300",
+            "gaid": "gaid",
+            "useragent": "ua",
+            "version": "29",
+            "maker": "HUAWEI",
+            "belongCountry": "RU"
+          },
+          "geo": {
+          },
+          "network": {
+            "carrier": 99,
+            "cellInfo": [
+              {
+                "mcc": "424",
+                "mnc": "3"
+              }
+            ],
+            "type": 1
+          },
+          "regs": {
+          },
+          "version": "3.4"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "ctrlSwitchs": "0",
+          "dsp1cost": 61,
+          "dspcost": 108,
+          "multiad": [
+            {
+              "adtype": 8,
+              "brsetting": "Y",
+              "content": [
+                {
+                  "clickActionList": [
+                    1
+                  ],
+                  "contentid": "58025103",
+                  "creativetype": 2,
+                  "endtime": 1621428898335,
+                  "filterList": [
+                    3
+                  ],
+                  "interactiontype": 1,
+                  "landingTitle": 1,
+                  "metaData": {
+                    "adSign": "2",
+                    "appPromotionChannel": "401721412",
+                    "clickUrl": "https://ads.huawei.com/usermgtportal/home/index.html#/",
+                    "imageInfo": [
+                      {
+                        "checkSha256Flag": 1,
+                        "height": 250,
+                        "imageType": "img",
+                        "sha256": "",
+                        "url": "https://ads.huawei.com/usermgtportal/home/img/huawei_logo_black.aaec817d.svg",
+                        "width": 300
+                      }
+                    ],
+                    "label": "Banner_API",
+                    "landingPageType": "3"
+                  },
+                  "monitor": [
+                    {
+                      "eventType": "click"
+                    },
+                    {
+                      "eventType": "imp",
+                      "url": [
+                      ]
+                    }
+                  ],
+                  "paramfromserver": {
+                    "a": "1||test",
+                    "sig": "",
+                    "t": "99990101235959"
+                  },
+                  "price": 2.8,
+                  "starttime": 1621267200000,
+                  "taskid": "48017658"
+                }
+              ],
+              "retcode30": 200,
+              "slotid": "m8x9x3rzff"
+            }
+          ],
+          "noReportAdTypeEventList": [
+            {
+              "adType": 8,
+              "eventTypeList": [
+                "exception_6"
+              ]
+            }
+          ],
+          "retcode": 200,
+          "totalCacheSize": 300
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<style> html, body  { margin: 0; padding: 0; width: 100%; height: 100%; vertical-align: middle; }  html  { display: table; }  body { display: table-cell; vertical-align: middle; text-align: center; -webkit-text-size-adjust: none; }  </style> <span class=\"title-link advertiser_label\"></span> <a href='https://ads.huawei.com/usermgtportal/home/index.html#/' style=\"text-decoration:none\" onclick=sendGetReq()> <img src='https://ads.huawei.com/usermgtportal/home/img/huawei_logo_black.aaec817d.svg' width='300' height='250'/> </a> <script type=\"text/javascript\">var dspClickTrackings = [];function sendGetReq() {sendSomeGetReq(dspClickTrackings)}function sendOneGetReq(url) {var req = new XMLHttpRequest();req.open('GET', url, true);req.send(null);}function sendSomeGetReq(urls) {for (var i = 0; i < urls.length; i++) {sendOneGetReq(urls[i]);}}</script>",
+            "adomain": [
+              "huaweiads"
+            ],
+            "h": 250,
+            "w": 300,
+            "crid": "58025103",
+            "id": "PrebidMobile",
+            "impid": "PrebidMobile",
+            "price": 2.8
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json
new file mode 100644
index 00000000..6ab59e5c
--- /dev/null
+++ b/adapters/huaweiads/huaweiadstest/exemplary/bannerTestExtraInfo3.json
@@ -0,0 +1,271 @@
+{
+  "mockBidRequest": {
+    "id": "a3b18c5b-6708-4bb7-b41b-40ed37d89561",
+    "source": {
+      "tid": "a3b18c5b-6708-4bb7-b41b-40ed37d89561"
+    },
+    "imp": [
+      {
+        "id": "PrebidMobile",
+        "secure": 1,
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ],
+          "api": [
+            5
+          ]
+        },
+        "ext": {
+          "prebid": {
+            "storedrequest": {
+              "id": "1001-1"
+            }
+          },
+          "bidder": {
+            "slotid": "m8x9x3rzff",
+            "adtype": "banner",
+            "publisherid": "123",
+            "signkey": "signkey",
+            "keyid": "41",
+            "isTestAuthorization": "true"
+          }
+        }
+      }
+    ],
+    "device": {
+      "make": "HUAWEI",
+      "model": "LYA-AL00",
+      "ua": "ua",
+      "lmt": 0,
+      "os": "android",
+      "osv": "29",
+      "language": "en",
+      "w": 360,
+      "h": 755,
+      "pxratio": 3,
+      "mccmnc": "424-3",
+      "carrier": "carrier",
+      "connectiontype": 1,
+      "geo": {
+        "country": "TUN"
+      }
+    },
+    "app": {
+      "bundle": "com.example3.unchanged",
+      "ver": "1.11",
+      "name": "API1.0Demo",
+      "publisher": {
+        "id": "1001"
+      },
+      "ext": {
+        "prebid": {
+          "source": "prebid-mobile",
+          "version": "1.11"
+        }
+      }
+    },
+    "user": {
+      "gender": "O",
+      "ext": {
+        "data": {
+          "gaid": [
+            "gaid"
+          ],
+          "oaid": [
+            "oaid"
+          ],
+          "clientTime": [
+            "2018-11-02 16:34:07.981+1300"
+          ]
+        }
+      }
+    },
+    "ext": {
+      "prebid": {
+        "storedrequest": {
+          "id": "1001"
+        },
+        "cache": {
+          "bids": {}
+        },
+        "targeting": {}
+      }
+    }
+  },
+  "httpcalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "ua"
+          ],
+          "Authorization": [
+            "Digest username=123,realm=ppsadx/getResult,nonce=1629473330823,response=d1d61a13a83e1468aa4dff5c8a6cee0b8b381173ca3eb6fa9b313937684d87c0,algorithm=HmacSHA256,usertype=1,keyid=41"
+          ]
+        },
+        "body": {
+          "app": {
+            "lang": "en",
+            "country": "TN",
+            "name": "API1.0Demo",
+            "pkgname": "com.example3.unchanged",
+            "version": "1.11"
+          },
+          "multislot": [
+            {
+              "adtype": 8,
+              "slotid": "m8x9x3rzff",
+              "test": 0,
+              "format": [
+                {
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ],
+          "device": {
+            "height": 755,
+            "language": "en",
+            "oaid": "oaid",
+            "os": "android",
+            "localeCountry": "TN",
+            "pxratio": 3,
+            "width": 360,
+            "model": "LYA-AL00",
+            "clientTime": "2018-11-02 16:34:07.981+1300",
+            "gaid": "gaid",
+            "useragent": "ua",
+            "version": "29",
+            "maker": "HUAWEI",
+            "belongCountry": "TN"
+          },
+          "geo": {
+          },
+          "network": {
+            "carrier": 99,
+            "cellInfo": [
+              {
+                "mcc": "424",
+                "mnc": "3"
+              }
+            ],
+            "type": 1
+          },
+          "regs": {
+          },
+          "version": "3.4"
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "ctrlSwitchs": "0",
+          "dsp1cost": 61,
+          "dspcost": 108,
+          "multiad": [
+            {
+              "adtype": 8,
+              "brsetting": "Y",
+              "content": [
+                {
+                  "clickActionList": [
+                    1
+                  ],
+                  "contentid": "58025103",
+                  "creativetype": 2,
+                  "endtime": 1621428898335,
+                  "filterList": [
+                    3
+                  ],
+                  "interactiontype": 1,
+                  "landingTitle": 1,
+                  "metaData": {
+                    "adSign": "2",
+                    "appPromotionChannel": "401721412",
+                    "clickUrl": "https://ads.huawei.com/usermgtportal/home/index.html#/",
+                    "imageInfo": [
+                      {
+                        "checkSha256Flag": 1,
+                        "height": 250,
+                        "imageType": "img",
+                        "sha256": "",
+                        "url": "https://ads.huawei.com/usermgtportal/home/img/huawei_logo_black.aaec817d.svg",
+                        "width": 300
+                      }
+                    ],
+                    "label": "Banner_API",
+                    "landingPageType": "3"
+                  },
+                  "monitor": [
+                    {
+                      "eventType": "click"
+                    },
+                    {
+                      "eventType": "imp",
+                      "url": [
+                      ]
+                    }
+                  ],
+                  "paramfromserver": {
+                    "a": "1||test",
+                    "sig": "",
+                    "t": "99990101235959"
+                  },
+                  "price": 2.8,
+                  "starttime": 1621267200000,
+                  "taskid": "48017658"
+                }
+              ],
+              "retcode30": 200,
+              "slotid": "m8x9x3rzff"
+            }
+          ],
+          "noReportAdTypeEventList": [
+            {
+              "adType": 8,
+              "eventTypeList": [
+                "exception_6"
+              ]
+            }
+          ],
+          "retcode": 200,
+          "totalCacheSize": 300
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "adm": "<style> html, body  { margin: 0; padding: 0; width: 100%; height: 100%; vertical-align: middle; }  html  { display: table; }  body { display: table-cell; vertical-align: middle; text-align: center; -webkit-text-size-adjust: none; }  </style> <span class=\"title-link advertiser_label\"></span> <a href='https://ads.huawei.com/usermgtportal/home/index.html#/' style=\"text-decoration:none\" onclick=sendGetReq()> <img src='https://ads.huawei.com/usermgtportal/home/img/huawei_logo_black.aaec817d.svg' width='300' height='250'/> </a> <script type=\"text/javascript\">var dspClickTrackings = [];function sendGetReq() {sendSomeGetReq(dspClickTrackings)}function sendOneGetReq(url) {var req = new XMLHttpRequest();req.open('GET', url, true);req.send(null);}function sendSomeGetReq(urls) {for (var i = 0; i < urls.length; i++) {sendOneGetReq(urls[i]);}}</script>",
+            "adomain": [
+              "huaweiads"
+            ],
+            "h": 250,
+            "w": 300,
+            "crid": "58025103",
+            "id": "PrebidMobile",
+            "impid": "PrebidMobile",
+            "price": 2.8
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json
index d804375c..ae3efabc 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json
@@ -65,7 +65,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json
index 62e2dcd6..ff8e686c 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json
@@ -28,8 +28,7 @@
     "device": {
       "ua": "useragent",
       "h": 1920,
-      "language": "zh",
-      "geoCountry": "CH",
+      "language": "en",
       "model": "COL-TEST",
       "os": "android",
       "osv": "10.0.0",
@@ -40,7 +39,7 @@
       "dnt": 0,
       "pxratio": 23.01,
       "geo": {
-        "country": ""
+        "country": "DEU"
       }
     },
     "user": {
@@ -64,7 +63,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dre.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
@@ -82,7 +81,7 @@
         "body": {
           "app": {
             "lang": "en",
-            "country": "ZA",
+            "country": "DE",
             "name": "Huawei Browser",
             "pkgname": "com.huawei.browser",
             "version": "9.1.0.301"
@@ -101,12 +100,12 @@
           ],
           "device": {
             "height": 1920,
-            "language": "zh",
+            "language": "en",
             "oaid": "oaid",
             "os": "android",
             "type": 4,
             "ip": "ip",
-            "localeCountry": "ZA",
+            "localeCountry": "DE",
             "pxratio": 23.01,
             "model": "COL-TEST",
             "width": 1080,
@@ -117,7 +116,7 @@
             "useragent": "useragent",
             "version": "10.0.0",
             "maker": "huawei",
-            "belongCountry": "ZA"
+            "belongCountry": "DE"
           },
           "geo": {
           },
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json
index a68d8b8a..22ac3556 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json
@@ -21,15 +21,14 @@
       }
     ],
     "app": {
-      "bundle": "com.huawei.browser",
+      "bundle": "com.huawei.p11",
       "name": "Huawei Browser",
       "ver": "9.1.0.301"
     },
     "device": {
       "ua": "useragent",
       "h": 1920,
-      "language": "zh",
-      "geoCountry": "CH",
+      "language": "en",
       "model": "COL-TEST",
       "os": "android",
       "osv": "10.0.0",
@@ -39,7 +38,7 @@
       "ip": "152.193.6.74",
       "pxratio": 23.01,
       "geo": {
-        "country": ""
+        "country": "ARG"
       }
     },
     "user": {
@@ -63,7 +62,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
@@ -81,9 +80,9 @@
         "body": {
           "app": {
             "lang": "en",
-            "country": "ZA",
+            "country": "AR",
             "name": "Huawei Browser",
-            "pkgname": "com.huawei.browser",
+            "pkgname": "com.example.pkgname2",
             "version": "9.1.0.301"
           },
           "multislot": [
@@ -100,12 +99,12 @@
           ],
           "device": {
             "height": 1920,
-            "language": "zh",
+            "language": "en",
             "oaid": "oaid",
             "os": "android",
             "type": 4,
             "ip": "152.193.6.74",
-            "localeCountry": "ZA",
+            "localeCountry": "AR",
             "pxratio": 23.01,
             "model": "COL-TEST",
             "width": 1080,
@@ -114,7 +113,7 @@
             "useragent": "useragent",
             "version": "10.0.0",
             "maker": "huawei",
-            "belongCountry": "ZA"
+            "belongCountry": "AR"
           },
           "geo": {
           },
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json
index a6372030..18f03538 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json
@@ -63,7 +63,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/video.json b/adapters/huaweiads/huaweiadstest/exemplary/video.json
index ec589d3d..64c54d5d 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/video.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/video.json
@@ -39,8 +39,7 @@
     "device": {
       "ua": "useragent",
       "h": 1920,
-      "language": "zh",
-      "geoCountry": "CH",
+      "language": "en",
       "model": "COL-TEST",
       "os": "android",
       "osv": "10.0.0",
@@ -50,7 +49,7 @@
       "ip": "ip",
       "pxratio": 23.01,
       "geo": {
-        "country": ""
+        "country": "ATA"
       }
     },
     "user": {
@@ -74,7 +73,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dre.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
@@ -92,7 +91,7 @@
         "body": {
           "app": {
             "lang": "en",
-            "country": "ZA",
+            "country": "AT",
             "name": "Huawei Browser",
             "pkgname": "com.wavehk.android",
             "version": "9.1.0.301"
@@ -106,12 +105,12 @@
           ],
           "device": {
             "height": 1920,
-            "language": "zh",
+            "language": "en",
             "oaid": "oaid",
             "os": "android",
             "type": 4,
             "ip": "ip",
-            "localeCountry": "ZA",
+            "localeCountry": "AT",
             "pxratio": 23.01,
             "width": 1080,
             "model": "COL-TEST",
@@ -120,7 +119,7 @@
             "useragent": "useragent",
             "version": "10.0.0",
             "maker": "huawei",
-            "belongCountry": "ZA"
+            "belongCountry": "AT"
           },
           "geo": {
           },
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response.json
index b064adb2..327004f9 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_400.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_400.json
index 6b42905b..e06af96a 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_400.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_400.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_503.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_503.json
index 032c8e9a..53b05eba 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_503.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_503.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json
index 7d691d11..c2cc3424 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_dont_find_impid.json
@@ -92,7 +92,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json
index e4e6ec18..f4e5457c 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json
@@ -63,7 +63,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json
index 5a04ff6b..adb456cb 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode30_204.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_210.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_210.json
index ff0fd39f..4d4cc062 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_210.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_210.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_408.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_408.json
index 7878aa88..e8778e46 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_408.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_408.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_500.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_500.json
index c3b9de07..cd6440d1 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_500.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_retcode_500.json
@@ -69,7 +69,7 @@
   "httpcalls": [
     {
       "expectedRequest": {
-        "uri": "https://huaweiads.com/adxtest/",
+        "uri": "https://adx-dra.op.hicloud.com/ppsadx/getResult",
         "headers": {
           "Accept": [
             "application/json"
diff --git a/adapters/vidoomy/params_test.go b/adapters/vidoomy/params_test.go
new file mode 100644
index 00000000..d910b654
--- /dev/null
+++ b/adapters/vidoomy/params_test.go
@@ -0,0 +1,57 @@
+package vidoomy
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// This file actually intends to test static/bidder-params/vidoomy.json
+//
+// These also validate the format of the external API: request.imp[i].ext.vidoomy
+
+// TestValidParams makes sure that the vidoomy schema accepts all imp.ext fields which we intend to support.
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderVidoomy, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected vidoomy params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the Vidoomy schema rejects all the imp.ext fields we don't support.
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderVidoomy, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"zoneId":"123"}`,
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`4.2`,
+	`[]`,
+	`{}`,
+	`{"notmid":"123"}`,
+	`{"zoneId":123}`,
+	`{"zoneId":""}`,
+}
diff --git a/adapters/vidoomy/vidoomy_test.go b/adapters/vidoomy/vidoomy_test.go
new file mode 100644
index 00000000..c9181395
--- /dev/null
+++ b/adapters/vidoomy/vidoomy_test.go
@@ -0,0 +1,34 @@
+package vidoomy
+
+import (
+	"testing"
+
+	"github.com/influxdata/influxdb/pkg/testing/assert"
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestVidoomyBidderEndpointConfig(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderVidoomy, config.Adapter{
+		Endpoint: "http://localhost/bid",
+	})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	bidderVidoomy := bidder.(*adapter)
+
+	assert.Equal(t, "http://localhost/bid", bidderVidoomy.endpoint)
+}
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderVidoomy, config.Adapter{})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "vidoomytest", bidder)
+}
diff --git a/adapters/vidoomy/vidoomytest/exemplary/multi-impression-video-banner.json b/adapters/vidoomy/vidoomytest/exemplary/multi-impression-video-banner.json
new file mode 100644
index 00000000..723248dd
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/exemplary/multi-impression-video-banner.json
@@ -0,0 +1,226 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      },
+      {
+        "id": "test-imp-video-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "X-Forwarded-For": [
+            "127.0.0.1"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "test-site-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "vidoomy",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    },
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "X-Forwarded-For": [
+            "127.0.0.1"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-video-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "test-site-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "cur": "USD",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "fe69dd6d-e85c-4186-80a7-605b530bc23b",
+                  "crid": "72745",
+                  "adomain": [
+                    "ad-domain.com"
+                  ],
+                  "price": 3,
+                  "impid": "test-imp-video-id",
+                  "adid": "564",
+                  "adm": "<?xml version=\"1.0\"?><VAST version=\"2.0\"></VAST>"
+                }
+              ],
+              "seat": "vidoomy"
+            }
+          ],
+          "id": "test-request-id"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    },
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "fe69dd6d-e85c-4186-80a7-605b530bc23b",
+            "crid": "72745",
+            "adomain": [
+              "ad-domain.com"
+            ],
+            "price": 3,
+            "impid": "test-imp-video-id",
+            "adid": "564",
+            "adm": "<?xml version=\"1.0\"?><VAST version=\"2.0\"></VAST>"
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/vidoomy/vidoomytest/exemplary/simple-app-banner.json b/adapters/vidoomy/vidoomytest/exemplary/simple-app-banner.json
new file mode 100644
index 00000000..145524ea
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/exemplary/simple-app-banner.json
@@ -0,0 +1,116 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "app": {
+      "id": "test-app-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "X-Forwarded-For": [
+            "127.0.0.1"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "app": {
+            "id": "test-app-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "vidoomy",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/vidoomy/vidoomytest/exemplary/simple-banner.json b/adapters/vidoomy/vidoomytest/exemplary/simple-banner.json
new file mode 100644
index 00000000..36d27856
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/exemplary/simple-banner.json
@@ -0,0 +1,116 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "X-Forwarded-For": [
+            "127.0.0.1"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "test-site-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "vidoomy",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "w": 728,
+            "h": 90
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/exemplary/simple-site-video.json b/adapters/vidoomy/vidoomytest/exemplary/simple-site-video.json
new file mode 100644
index 00000000..d2d6e028
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/exemplary/simple-site-video.json
@@ -0,0 +1,121 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-video-id",
+        "video": {
+          "w": 900,
+          "h": 250,
+          "mimes": [
+            "video/x-flv",
+            "video/mp4"
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "site": {
+      "id": "test",
+      "publisher": {
+        "id": "123"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "method": "GET",
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-video-id",
+              "video": {
+                "w": 900,
+                "h": 250,
+                "mimes": [
+                  "video/x-flv",
+                  "video/mp4"
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "test",
+            "publisher": {
+              "id": "123"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "cur": "USD",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "fe69dd6d-e85c-4186-80a7-605b530bc23b",
+                  "crid": "72745",
+                  "adomain": [
+                    "ad-domain.com"
+                  ],
+                  "price": 3,
+                  "impid": "test-imp-video-id",
+                  "adid": "564",
+                  "adm": "<?xml version=\"1.0\"?><VAST version=\"2.0\"></VAST>"
+                }
+              ],
+              "seat": "vidoomy"
+            }
+          ],
+          "id": "test-request-id"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "fe69dd6d-e85c-4186-80a7-605b530bc23b",
+            "crid": "72745",
+            "adomain": [
+              "ad-domain.com"
+            ],
+            "price": 3,
+            "impid": "test-imp-video-id",
+            "adid": "564",
+            "adm": "<?xml version=\"1.0\"?><VAST version=\"2.0\"></VAST>"
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/supplemental/server-error.json b/adapters/vidoomy/vidoomytest/supplemental/server-error.json
new file mode 100644
index 00000000..ebeedb14
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/supplemental/server-error.json
@@ -0,0 +1,70 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "site-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "site-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 500,
+        "body": {
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 500.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/supplemental/server-response-wrong-impid.json b/adapters/vidoomy/vidoomytest/supplemental/server-response-wrong-impid.json
new file mode 100644
index 00000000..dad8f7cc
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/supplemental/server-response-wrong-impid.json
@@ -0,0 +1,103 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "site-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "X-Forwarded-For": [
+            "127.0.0.1"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ip": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "site-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "vidoomy",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "wrong",
+                "price": 0.500000,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 90,
+                "w": 728
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unknown ad unit code 'wrong'",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/supplemental/simple-banner-no-response.json b/adapters/vidoomy/vidoomytest/supplemental/simple-banner-no-response.json
new file mode 100644
index 00000000..0964351a
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/supplemental/simple-banner-no-response.json
@@ -0,0 +1,85 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}],
+          "w": 728,
+          "h": 90
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ipv6": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Accept": [
+            "application/json"
+          ],
+          "Content-Type": [
+            "application/json;charset=utf-8"
+          ],
+          "User-Agent": [
+            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"
+          ],
+          "X-Openrtb-Version": [
+            "2.5"
+          ],
+          "X-Forwarded-For": [
+            "127.0.0.1"
+          ]
+        },
+        "uri": "",
+        "body": {
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+            "ipv6": "127.0.0.1"
+          },
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [{"w": 728, "h": 90}],
+                "w": 728,
+                "h": 90
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone-id-123"
+                }
+              }
+            }
+          ],
+          "site": {
+            "id": "test-site-id"
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {}
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-format.json b/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-format.json
new file mode 100644
index 00000000..e38f37f4
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-format.json
@@ -0,0 +1,32 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": []
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "no sizes provided for Banner []",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-width-high.json b/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-width-high.json
new file mode 100644
index 00000000..b5c22546
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-width-high.json
@@ -0,0 +1,34 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}],
+          "w": 0,
+          "h": 720
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "invalid sizes provided for Banner 0 x 720",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-with-format.json b/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-with-format.json
new file mode 100644
index 00000000..e4541c9c
--- /dev/null
+++ b/adapters/vidoomy/vidoomytest/supplemental/wrong-banner-with-format.json
@@ -0,0 +1,34 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [{"w": 728, "h": 90}],
+          "w": 0,
+          "h" : 90
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone-id-123"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
+      "ip": "127.0.0.1"
+    },
+    "site": {
+      "id": "test-site-id"
+    }
+  },
+
+  "expectedMakeRequestsErrors": [
+    {
+      "value": "invalid sizes provided for Banner 0 x 90",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go
index 62b0b604..d266bc38 100644
--- a/endpoints/openrtb2/amp_auction_test.go
+++ b/endpoints/openrtb2/amp_auction_test.go
@@ -1266,7 +1266,7 @@ func TestBuildAmpObject(t *testing.T) {
 
 	for _, test := range testCases {
 		// Set up test, declare a new mock logger every time
-		actualAmpObject, endpoint := AmpObjectTestSetup(t, test.inTagId, test.inStoredRequest, false)
+		actualAmpObject, endpoint := ampObjectTestSetup(t, test.inTagId, test.inStoredRequest, false)
 		// Run test
 		endpoint(recorder, request, nil)
 
@@ -1332,13 +1332,13 @@ func TestIdGeneration(t *testing.T) {
 
 	for _, test := range testCases {
 		// Set up and run test
-		actualAmpObject, endpoint := AmpObjectTestSetup(t, "test", test.givenInStoredRequest, test.givenGenerateRequestID)
+		actualAmpObject, endpoint := ampObjectTestSetup(t, "test", test.givenInStoredRequest, test.givenGenerateRequestID)
 		endpoint(recorder, request, nil)
 		assert.Equalf(t, test.expectedID, actualAmpObject.Request.ID, "Bid Request ID is incorrect: %s\n", test.description)
 	}
 }
 
-func AmpObjectTestSetup(t *testing.T, inTagId string, inStoredRequest json.RawMessage, generateRequestID bool) (*analytics.AmpObject, httprouter.Handle) {
+func ampObjectTestSetup(t *testing.T, inTagId string, inStoredRequest json.RawMessage, generateRequestID bool) (*analytics.AmpObject, httprouter.Handle) {
 	actualAmpObject := analytics.AmpObject{}
 	logger := newMockLogger(&actualAmpObject)
 
@@ -1363,3 +1363,65 @@ func AmpObjectTestSetup(t *testing.T, inTagId string, inStoredRequest json.RawMe
 	)
 	return &actualAmpObject, endpoint
 }
+
+func TestAmpAuctionResponseHeaders(t *testing.T) {
+	testCases := []struct {
+		description         string
+		requestURLArguments string
+		expectedStatus      int
+		expectedHeaders     func(http.Header)
+	}{
+		{
+			description:         "Success Response",
+			requestURLArguments: "?tag_id=1&__amp_source_origin=foo",
+			expectedStatus:      200,
+			expectedHeaders: func(h http.Header) {
+				h.Set("AMP-Access-Control-Allow-Source-Origin", "foo")
+				h.Set("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin")
+				h.Set("X-Prebid", "pbs-go/unknown")
+				h.Set("Content-Type", "text/plain; charset=utf-8")
+			},
+		},
+		{
+			description:         "Failure Response",
+			requestURLArguments: "?tag_id=invalid&__amp_source_origin=foo",
+			expectedStatus:      400,
+			expectedHeaders: func(h http.Header) {
+				h.Set("AMP-Access-Control-Allow-Source-Origin", "foo")
+				h.Set("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin")
+				h.Set("X-Prebid", "pbs-go/unknown")
+			},
+		},
+	}
+
+	storedRequests := map[string]json.RawMessage{
+		"1": json.RawMessage(validRequest(t, "site.json")),
+	}
+	exchange := &nobidExchange{}
+	endpoint, _ := NewAmpEndpoint(
+		fakeUUIDGenerator{},
+		exchange,
+		newParamsValidator(t),
+		&mockAmpStoredReqFetcher{storedRequests},
+		empty_fetcher.EmptyFetcher{},
+		&config.Configuration{MaxRequestSize: maxSize},
+		&metricsConfig.NilMetricsEngine{},
+		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
+		map[string]string{},
+		[]byte{},
+		openrtb_ext.BuildBidderMap(),
+	)
+
+	for _, test := range testCases {
+		httpReq := httptest.NewRequest("GET", fmt.Sprintf("/openrtb2/auction/amp"+test.requestURLArguments), nil)
+		recorder := httptest.NewRecorder()
+
+		endpoint(recorder, httpReq, nil)
+
+		expectedHeaders := http.Header{}
+		test.expectedHeaders(expectedHeaders)
+
+		assert.Equal(t, test.expectedStatus, recorder.Result().StatusCode, test.description+":statuscode")
+		assert.Equal(t, expectedHeaders, recorder.Result().Header, test.description+":statuscode")
+	}
+}
diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go
index c42580fc..9b2bf1dd 100644
--- a/endpoints/openrtb2/auction_test.go
+++ b/endpoints/openrtb2/auction_test.go
@@ -3577,6 +3577,61 @@ func TestValidateNativeAssetData(t *testing.T) {
 	}
 }
 
+func TestAuctionResponseHeaders(t *testing.T) {
+	testCases := []struct {
+		description     string
+		requestBody     string
+		expectedStatus  int
+		expectedHeaders func(http.Header)
+	}{
+		{
+			description:    "Success Response",
+			requestBody:    validRequest(t, "site.json"),
+			expectedStatus: 200,
+			expectedHeaders: func(h http.Header) {
+				h.Set("X-Prebid", "pbs-go/unknown")
+				h.Set("Content-Type", "application/json")
+			},
+		},
+		{
+			description:    "Failure Response",
+			requestBody:    "{}",
+			expectedStatus: 400,
+			expectedHeaders: func(h http.Header) {
+				h.Set("X-Prebid", "pbs-go/unknown")
+			},
+		},
+	}
+
+	exchange := &nobidExchange{}
+	endpoint, _ := NewEndpoint(
+		fakeUUIDGenerator{},
+		exchange,
+		newParamsValidator(t),
+		empty_fetcher.EmptyFetcher{},
+		empty_fetcher.EmptyFetcher{},
+		&config.Configuration{MaxRequestSize: maxSize},
+		&metricsConfig.NilMetricsEngine{},
+		analyticsConf.NewPBSAnalytics(&config.Analytics{}),
+		map[string]string{},
+		[]byte{},
+		openrtb_ext.BuildBidderMap(),
+		empty_fetcher.EmptyFetcher{})
+
+	for _, test := range testCases {
+		httpReq := httptest.NewRequest("POST", "/openrtb2/auction", strings.NewReader(test.requestBody))
+		recorder := httptest.NewRecorder()
+
+		endpoint(recorder, httpReq, nil)
+
+		expectedHeaders := http.Header{}
+		test.expectedHeaders(expectedHeaders)
+
+		assert.Equal(t, test.expectedStatus, recorder.Result().StatusCode, test.description+":statuscode")
+		assert.Equal(t, expectedHeaders, recorder.Result().Header, test.description+":statuscode")
+	}
+}
+
 // warningsCheckExchange is a well-behaved exchange which stores all incoming warnings.
 type warningsCheckExchange struct {
 	auctionRequest exchange.AuctionRequest
diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go
index 91512a2e..c4d8602a 100644
--- a/endpoints/openrtb2/video_auction_test.go
+++ b/endpoints/openrtb2/video_auction_test.go
@@ -1,7 +1,6 @@
 package openrtb2
 
 import (
-	"bytes"
 	"context"
 	"encoding/json"
 	"errors"
@@ -29,11 +28,7 @@ import (
 
 func TestVideoEndpointImpressionsNumber(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -62,16 +57,11 @@ func TestVideoEndpointImpressionsNumber(t *testing.T) {
 	assert.Len(t, resp.AdPods[4].Targeting, 3, "Incorrect Targeting data in response")
 
 	assert.Equal(t, resp.AdPods[4].Targeting[0].HbPbCatDur, "20.00_395_30s", "Incorrect number of Ad Pods in response")
-
 }
 
 func TestVideoEndpointImpressionsDuration(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_different_durations.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_different_durations.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -102,7 +92,6 @@ func TestVideoEndpointImpressionsDuration(t *testing.T) {
 	assert.Equal(t, ex.lastRequest.Imp[17].ID, "2_5", "Incorrect impression id in request")
 	assert.Equal(t, ex.lastRequest.Imp[17].Video.MaxDuration, int64(30), "Incorrect impression max duration in request")
 	assert.Equal(t, ex.lastRequest.Imp[17].Video.MinDuration, int64(30), "Incorrect impression min duration in request")
-
 }
 
 func TestCreateBidExtension(t *testing.T) {
@@ -143,7 +132,6 @@ func TestCreateBidExtension(t *testing.T) {
 	}
 	assert.Equal(t, resExt.Prebid.Targeting.DurationRangeSec, durationRange, "Duration range seconds is incorrect")
 	assert.Equal(t, resExt.Prebid.Targeting.PriceGranularity.Ranges, priceGranRanges, "Price granularity is incorrect")
-
 }
 
 func TestCreateBidExtensionExactDurTrueNoPriceRange(t *testing.T) {
@@ -183,11 +171,7 @@ func TestVideoEndpointDebugQueryTrue(t *testing.T) {
 	ex := &mockExchangeVideo{
 		cache: &mockCacheClient{},
 	}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video?debug=true", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -225,11 +209,7 @@ func TestVideoEndpointDebugQueryFalse(t *testing.T) {
 	ex := &mockExchangeVideo{
 		cache: &mockCacheClient{},
 	}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video?debug=123", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -267,11 +247,7 @@ func TestVideoEndpointDebugError(t *testing.T) {
 	ex := &mockExchangeVideo{
 		cache: &mockCacheClient{},
 	}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_invalid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_invalid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video?debug=true", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -289,11 +265,7 @@ func TestVideoEndpointDebugNoAdPods(t *testing.T) {
 	ex := &mockExchangeVideoNoBids{
 		cache: &mockCacheClient{},
 	}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video?debug=true", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -323,11 +295,7 @@ func TestVideoEndpointDebugNoAdPods(t *testing.T) {
 
 func TestVideoEndpointNoPods(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_invalid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_invalid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -877,11 +845,7 @@ func TestHandleError(t *testing.T) {
 
 func TestHandleErrorMetrics(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_invalid_sample.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_invalid_sample.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -899,87 +863,64 @@ func TestHandleErrorMetrics(t *testing.T) {
 
 func TestParseVideoRequestWithUserAgentAndHeader(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_with_device_user_agent.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_with_device_user_agent.json")
 	headers := http.Header{}
 	headers.Add("User-Agent", "TestHeader")
 
 	deps := mockDeps(t, ex)
-	reqBody := string(getRequestPayload(t, reqData))
 	req, valErr, podErr := deps.parseVideoRequest([]byte(reqBody), headers)
 
 	assert.Equal(t, "TestHeaderSample", req.Device.UA, "Header should be taken from original request")
 	assert.Equal(t, []error(nil), valErr, "No validation errors should be returned")
 	assert.Equal(t, make([]PodError, 0), podErr, "No pod errors should be returned")
-
 }
 
 func TestParseVideoRequestWithUserAgentAndEmptyHeader(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_with_device_user_agent.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_with_device_user_agent.json")
 
 	headers := http.Header{}
 
 	deps := mockDeps(t, ex)
-	reqBody := string(getRequestPayload(t, reqData))
 	req, valErr, podErr := deps.parseVideoRequest([]byte(reqBody), headers)
 
 	assert.Equal(t, "TestHeaderSample", req.Device.UA, "Header should be taken from original request")
 	assert.Equal(t, []error(nil), valErr, "No validation errors should be returned")
 	assert.Equal(t, make([]PodError, 0), podErr, "No pod errors should be returned")
-
 }
 
 func TestParseVideoRequestWithoutUserAgentWithHeader(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_without_device_user_agent.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_without_device_user_agent.json")
 	headers := http.Header{}
 	headers.Add("User-Agent", "TestHeader")
 
 	deps := mockDeps(t, ex)
-	reqBody := string(getRequestPayload(t, reqData))
 	req, valErr, podErr := deps.parseVideoRequest([]byte(reqBody), headers)
 
 	assert.Equal(t, "TestHeader", req.Device.UA, "Device.ua should be taken from request header")
 	assert.Equal(t, []error(nil), valErr, "No validation errors should be returned")
 	assert.Equal(t, make([]PodError, 0), podErr, "No pod errors should be returned")
-
 }
 
 func TestParseVideoRequestWithoutUserAgentAndEmptyHeader(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_without_device_user_agent.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_without_device_user_agent.json")
 
 	headers := http.Header{}
 
 	deps := mockDeps(t, ex)
-	reqBody := string(getRequestPayload(t, reqData))
+
 	req, valErr, podErr := deps.parseVideoRequest([]byte(reqBody), headers)
 
 	assert.Equal(t, "", req.Device.UA, "Device.ua should be empty")
 	assert.Equal(t, []error(nil), valErr, "No validation errors should be returned")
 	assert.Equal(t, make([]PodError, 0), podErr, "No pod errors should be returned")
-
 }
 
 func TestParseVideoRequestWithEncodedUserAgentInHeader(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_without_device_user_agent.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_without_device_user_agent.json")
 
 	uaEncoded := "Mozilla%2F5.0%20%28Macintosh%3B%20Intel%20Mac%20OS%20X%2010_14_6%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F78.0.3904.87%20Safari%2F537.36"
 	uaDecoded := "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
@@ -988,21 +929,16 @@ func TestParseVideoRequestWithEncodedUserAgentInHeader(t *testing.T) {
 	headers.Add("User-Agent", uaEncoded)
 
 	deps := mockDeps(t, ex)
-	reqBody := string(getRequestPayload(t, reqData))
 	req, valErr, podErr := deps.parseVideoRequest([]byte(reqBody), headers)
 
 	assert.Equal(t, uaDecoded, req.Device.UA, "Device.ua should be taken from request header")
 	assert.Equal(t, []error(nil), valErr, "No validation errors should be returned")
 	assert.Equal(t, make([]PodError, 0), podErr, "No pod errors should be returned")
-
 }
 
 func TestParseVideoRequestWithDecodedUserAgentInHeader(t *testing.T) {
 	ex := &mockExchangeVideo{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_without_device_user_agent.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_without_device_user_agent.json")
 
 	uaDecoded := "Mozilla/5.0+(Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
 
@@ -1010,13 +946,11 @@ func TestParseVideoRequestWithDecodedUserAgentInHeader(t *testing.T) {
 	headers.Add("User-Agent", uaDecoded)
 
 	deps := mockDeps(t, ex)
-	reqBody := string(getRequestPayload(t, reqData))
 	req, valErr, podErr := deps.parseVideoRequest([]byte(reqBody), headers)
 
 	assert.Equal(t, uaDecoded, req.Device.UA, "Device.ua should be taken from request header")
 	assert.Equal(t, []error(nil), valErr, "No validation errors should be returned")
 	assert.Equal(t, make([]PodError, 0), podErr, "No pod errors should be returned")
-
 }
 
 func TestHandleErrorDebugLog(t *testing.T) {
@@ -1111,15 +1045,10 @@ func TestCCPA(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		// Load Test Request
-		requestContainerBytes, err := ioutil.ReadFile(test.testFilePath)
-		if err != nil {
-			t.Fatalf("%s: Failed to fetch a valid request: %v", test.description, err)
-		}
-		requestBytes := getRequestPayload(t, requestContainerBytes)
+		reqBody := readVideoTestFile(t, test.testFilePath)
 
 		// Create HTTP Request + Response Recorder
-		httpRequest := httptest.NewRequest("POST", "/openrtb2/video", bytes.NewReader(requestBytes))
+		httpRequest := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
 		httpResponseRecorder := httptest.NewRecorder()
 
 		// Run Test
@@ -1132,7 +1061,7 @@ func TestCCPA(t *testing.T) {
 			t.Fatalf("%s: The request never made it into the exchange.", test.description)
 		}
 		extRegs := &openrtb_ext.ExtRegs{}
-		if err = json.Unmarshal(ex.lastRequest.Regs.Ext, extRegs); err != nil {
+		if err := json.Unmarshal(ex.lastRequest.Regs.Ext, extRegs); err != nil {
 			t.Fatalf("%s: Failed to unmarshal reg.ext in request to the exchange: %v", test.description, err)
 		}
 		if test.expectConsentString {
@@ -1154,11 +1083,7 @@ func TestCCPA(t *testing.T) {
 
 func TestVideoEndpointAppendBidderNames(t *testing.T) {
 	ex := &mockExchangeAppendBidderNames{}
-	reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_appendbiddernames.json")
-	if err != nil {
-		t.Fatalf("Failed to fetch a valid request: %v", err)
-	}
-	reqBody := string(getRequestPayload(t, reqData))
+	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_appendbiddernames.json")
 	req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
 	recorder := httptest.NewRecorder()
 
@@ -1191,7 +1116,6 @@ func TestVideoEndpointAppendBidderNames(t *testing.T) {
 	assert.Len(t, resp.AdPods[4].Targeting, 3, "Incorrect Targeting data in response")
 
 	assert.Equal(t, resp.AdPods[4].Targeting[0].HbPbCatDur, "20.00_395_30s_appnexus", "Incorrect number of Ad Pods in response")
-
 }
 
 func TestFormatTargetingKey(t *testing.T) {
@@ -1204,6 +1128,50 @@ func TestFormatTargetingKeyLongKey(t *testing.T) {
 	assert.Equal(t, "hb_pb_20.00", res, "Tergeting key constructed incorrectly")
 }
 
+func TestVideoAuctionResponseHeaders(t *testing.T) {
+	testCases := []struct {
+		description     string
+		givenTestFile   string
+		expectedStatus  int
+		expectedHeaders func(http.Header)
+	}{
+		{
+			description:    "Success Response",
+			givenTestFile:  "sample-requests/video/video_valid_sample.json",
+			expectedStatus: 200,
+			expectedHeaders: func(h http.Header) {
+				h.Set("X-Prebid", "pbs-go/unknown")
+				h.Set("Content-Type", "application/json")
+			},
+		}, {
+			description:    "Failure Response",
+			givenTestFile:  "sample-requests/video/video_invalid_sample.json",
+			expectedStatus: 500,
+			expectedHeaders: func(h http.Header) {
+				h.Set("X-Prebid", "pbs-go/unknown")
+			},
+		},
+	}
+
+	exchange := &mockExchangeVideo{}
+	endpoint := mockDeps(t, exchange)
+
+	for _, test := range testCases {
+		requestBody := readVideoTestFile(t, test.givenTestFile)
+
+		httpReq := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(requestBody))
+		recorder := httptest.NewRecorder()
+
+		endpoint.VideoAuctionEndpoint(recorder, httpReq, nil)
+
+		expectedHeaders := http.Header{}
+		test.expectedHeaders(expectedHeaders)
+
+		assert.Equal(t, test.expectedStatus, recorder.Result().StatusCode, test.description+":statuscode")
+		assert.Equal(t, expectedHeaders, recorder.Result().Header, test.description+":statuscode")
+	}
+}
+
 func mockDepsWithMetrics(t *testing.T, ex *mockExchangeVideo) (*endpointDeps, *metrics.Metrics, *mockAnalyticsModule) {
 	mockModule := &mockAnalyticsModule{}
 
@@ -1253,7 +1221,7 @@ func (m *mockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject) { return }
 func (m *mockAnalyticsModule) LogNotificationEventObject(ne *analytics.NotificationEvent) { return }
 
 func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps {
-	deps := &endpointDeps{
+	return &endpointDeps{
 		fakeUUIDGenerator{},
 		ex,
 		newParamsValidator(t),
@@ -1272,8 +1240,6 @@ func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps {
 		hardcodedResponseIPValidator{response: true},
 		empty_fetcher.EmptyFetcher{},
 	}
-
-	return deps
 }
 
 func mockDepsAppendBidderNames(t *testing.T, ex *mockExchangeAppendBidderNames) *endpointDeps {
@@ -1443,3 +1409,12 @@ var testVideoStoredImpData = map[string]json.RawMessage{
 var testVideoStoredRequestData = map[string]json.RawMessage{
 	"80ce30c53c16e6ede735f123ef6e32361bfc7b22": json.RawMessage(`{"accountid": "11223344", "site": {"page": "mygame.foo.com"}}`),
 }
+
+func readVideoTestFile(t *testing.T, filename string) string {
+	requestData, err := ioutil.ReadFile(filename)
+	if err != nil {
+		t.Fatalf("Failed to fetch a valid request: %v", err)
+	}
+
+	return string(getRequestPayload(t, requestData))
+}
diff --git a/exchange/adapter_util_test.go b/exchange/adapter_util_test.go
index b3a05cdc..9f2c7b8f 100644
--- a/exchange/adapter_util_test.go
+++ b/exchange/adapter_util_test.go
@@ -238,6 +238,7 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 			bidderInfos: map[string]config.BidderInfo{},
 			expected: map[string]string{
 				"lifestreet": `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":     `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 			},
 		},
 		{
@@ -245,6 +246,7 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 			bidderInfos: map[string]config.BidderInfo{"appnexus": infoEnabled},
 			expected: map[string]string{
 				"lifestreet": `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":     `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 			},
 		},
 		{
@@ -252,6 +254,7 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 			bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled},
 			expected: map[string]string{
 				"lifestreet": `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":     `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 				"appnexus":   `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
 			},
 		},
@@ -260,6 +263,7 @@ func TestGetDisabledBiddersErrorMessages(t *testing.T) {
 			bidderInfos: map[string]config.BidderInfo{"appnexus": infoDisabled, "openx": infoEnabled},
 			expected: map[string]string{
 				"lifestreet": `Bidder "lifestreet" is no longer available in Prebid Server. Please update your configuration.`,
+				"adagio":     `Bidder "adagio" is no longer available in Prebid Server. Please update your configuration.`,
 				"appnexus":   `Bidder "appnexus" has been disabled on this instance of Prebid Server. Please work with the PBS host to enable this bidder again.`,
 			},
 		},
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index f67b6ffb..e250b65e 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -2513,120 +2513,6 @@ func TestRemoveUnpermissionedEidsEmptyValidations(t *testing.T) {
 	}
 }
 
-func TestBuildXPrebidHeader(t *testing.T) {
-	testCases := []struct {
-		description   string
-		version       string
-		requestExt    *openrtb_ext.ExtRequest
-		requestAppExt *openrtb_ext.ExtApp
-		result        string
-	}{
-		{
-			description: "No versions",
-			version:     "",
-			result:      "pbs-go/unknown",
-		},
-		{
-			description: "pbs",
-			version:     "test-version",
-			result:      "pbs-go/test-version",
-		},
-		{
-			description: "prebid.js",
-			version:     "test-version",
-			requestExt: &openrtb_ext.ExtRequest{
-				Prebid: openrtb_ext.ExtRequestPrebid{
-					Channel: &openrtb_ext.ExtRequestPrebidChannel{
-						Name:    "pbjs",
-						Version: "test-pbjs-version",
-					},
-				},
-			},
-			result: "pbs-go/test-version,pbjs/test-pbjs-version",
-		},
-		{
-			description: "unknown prebid.js",
-			version:     "test-version",
-			requestExt: &openrtb_ext.ExtRequest{
-				Prebid: openrtb_ext.ExtRequestPrebid{
-					Channel: &openrtb_ext.ExtRequestPrebidChannel{
-						Name: "pbjs",
-					},
-				},
-			},
-			result: "pbs-go/test-version,pbjs/unknown",
-		},
-		{
-			description: "channel without a name",
-			version:     "test-version",
-			requestExt: &openrtb_ext.ExtRequest{
-				Prebid: openrtb_ext.ExtRequestPrebid{
-					Channel: &openrtb_ext.ExtRequestPrebidChannel{
-						Version: "test-version",
-					},
-				},
-			},
-			result: "pbs-go/test-version",
-		},
-		{
-			description: "prebid-mobile",
-			version:     "test-version",
-			requestAppExt: &openrtb_ext.ExtApp{
-				Prebid: openrtb_ext.ExtAppPrebid{
-					Source:  "prebid-mobile",
-					Version: "test-prebid-mobile-version",
-				},
-			},
-			result: "pbs-go/test-version,prebid-mobile/test-prebid-mobile-version",
-		},
-		{
-			description: "app ext without a source",
-			version:     "test-version",
-			requestAppExt: &openrtb_ext.ExtApp{
-				Prebid: openrtb_ext.ExtAppPrebid{
-					Version: "test-version",
-				},
-			},
-			result: "pbs-go/test-version",
-		},
-		{
-			description: "Version found in both req.Ext and req.App.Ext",
-			version:     "test-version",
-			requestExt: &openrtb_ext.ExtRequest{
-				Prebid: openrtb_ext.ExtRequestPrebid{
-					Channel: &openrtb_ext.ExtRequestPrebidChannel{
-						Name:    "pbjs",
-						Version: "test-pbjs-version",
-					},
-				},
-			},
-			requestAppExt: &openrtb_ext.ExtApp{
-				Prebid: openrtb_ext.ExtAppPrebid{
-					Source:  "prebid-mobile",
-					Version: "test-prebid-mobile-version",
-				},
-			},
-			result: "pbs-go/test-version,pbjs/test-pbjs-version,prebid-mobile/test-prebid-mobile-version",
-		},
-	}
-
-	for _, test := range testCases {
-		req := &openrtb2.BidRequest{}
-		if test.requestExt != nil {
-			reqExt, err := json.Marshal(test.requestExt)
-			assert.NoError(t, err, test.description+":err marshalling reqExt")
-			req.Ext = reqExt
-		}
-		if test.requestAppExt != nil {
-			reqAppExt, err := json.Marshal(test.requestAppExt)
-			assert.NoError(t, err, test.description+":err marshalling reqAppExt")
-			req.App = &openrtb2.App{Ext: reqAppExt}
-		}
-		result := buildXPrebidHeader(req, test.version)
-		assert.Equal(t, test.result, result, test.description+":result")
-	}
-}
-
 func TestCleanOpenRTBRequestsSChainMultipleBidders(t *testing.T) {
 	req := &openrtb2.BidRequest{
 		Site: &openrtb2.Site{},
diff --git a/version/xprebidheader_test.go b/version/xprebidheader_test.go
new file mode 100644
index 00000000..1529a8f7
--- /dev/null
+++ b/version/xprebidheader_test.go
@@ -0,0 +1,149 @@
+package version
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestBuildXPrebidHeader(t *testing.T) {
+	testCases := []struct {
+		description string
+		version     string
+		result      string
+	}{
+		{
+			description: "No Version",
+			version:     "",
+			result:      "pbs-go/unknown",
+		},
+		{
+			description: "Version",
+			version:     "0.100.0",
+			result:      "pbs-go/0.100.0",
+		},
+	}
+
+	for _, test := range testCases {
+		result := BuildXPrebidHeader(test.version)
+		assert.Equal(t, test.result, result, test.description)
+	}
+}
+
+func TestBuildXPrebidHeaderForRequest(t *testing.T) {
+	testCases := []struct {
+		description   string
+		version       string
+		requestExt    *openrtb_ext.ExtRequest
+		requestAppExt *openrtb_ext.ExtApp
+		result        string
+	}{
+		{
+			description: "No versions",
+			version:     "",
+			result:      "pbs-go/unknown",
+		},
+		{
+			description: "pbs",
+			version:     "test-version",
+			result:      "pbs-go/test-version",
+		},
+		{
+			description: "prebid.js",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Name:    "pbjs",
+						Version: "test-pbjs-version",
+					},
+				},
+			},
+			result: "pbs-go/test-version,pbjs/test-pbjs-version",
+		},
+		{
+			description: "unknown prebid.js",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Name: "pbjs",
+					},
+				},
+			},
+			result: "pbs-go/test-version,pbjs/unknown",
+		},
+		{
+			description: "channel without a name",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Version: "test-version",
+					},
+				},
+			},
+			result: "pbs-go/test-version",
+		},
+		{
+			description: "prebid-mobile",
+			version:     "test-version",
+			requestAppExt: &openrtb_ext.ExtApp{
+				Prebid: openrtb_ext.ExtAppPrebid{
+					Source:  "prebid-mobile",
+					Version: "test-prebid-mobile-version",
+				},
+			},
+			result: "pbs-go/test-version,prebid-mobile/test-prebid-mobile-version",
+		},
+		{
+			description: "app ext without a source",
+			version:     "test-version",
+			requestAppExt: &openrtb_ext.ExtApp{
+				Prebid: openrtb_ext.ExtAppPrebid{
+					Version: "test-version",
+				},
+			},
+			result: "pbs-go/test-version",
+		},
+		{
+			description: "Version found in both req.Ext and req.App.Ext",
+			version:     "test-version",
+			requestExt: &openrtb_ext.ExtRequest{
+				Prebid: openrtb_ext.ExtRequestPrebid{
+					Channel: &openrtb_ext.ExtRequestPrebidChannel{
+						Name:    "pbjs",
+						Version: "test-pbjs-version",
+					},
+				},
+			},
+			requestAppExt: &openrtb_ext.ExtApp{
+				Prebid: openrtb_ext.ExtAppPrebid{
+					Source:  "prebid-mobile",
+					Version: "test-prebid-mobile-version",
+				},
+			},
+			result: "pbs-go/test-version,pbjs/test-pbjs-version,prebid-mobile/test-prebid-mobile-version",
+		},
+	}
+
+	for _, test := range testCases {
+		req := &openrtb2.BidRequest{}
+		if test.requestExt != nil {
+			reqExt, err := json.Marshal(test.requestExt)
+			assert.NoError(t, err, test.description+":err marshalling reqExt")
+			req.Ext = reqExt
+		}
+		if test.requestAppExt != nil {
+			reqAppExt, err := json.Marshal(test.requestAppExt)
+			assert.NoError(t, err, test.description+":err marshalling reqAppExt")
+			req.App = &openrtb2.App{Ext: reqAppExt}
+		}
+		result := BuildXPrebidHeaderForRequest(req, test.version)
+		assert.Equal(t, test.result, result, test.description+":result")
+	}
+}