From dc9041a3a2d56f3e6387e6e5bc581391969d9237 Mon Sep 17 00:00:00 2001 From: pm-avinash-kapre <112699665+AvinashKapre@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:50:36 +0530 Subject: [PATCH 01/24] UOE-10974: Bug-fix- PubMatic-Secondary and pubmatic alias partners are not consuming PublisherID Configured at Partner Account Level (#885) --- .../openwrap/beforevalidationhook_test.go | 5 +- .../openwrap/bidderparams/pubmatic.go | 42 ++- .../openwrap/bidderparams/pubmatic_test.go | 297 +++++++++++++++++- 3 files changed, 322 insertions(+), 22 deletions(-) diff --git a/modules/pubmatic/openwrap/beforevalidationhook_test.go b/modules/pubmatic/openwrap/beforevalidationhook_test.go index bc14a7bbfb2..a31dcc803ed 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook_test.go +++ b/modules/pubmatic/openwrap/beforevalidationhook_test.go @@ -3967,6 +3967,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { models.BidderCode: "pub2-alias", models.IsAlias: "1", models.TIMEOUT: "200", + models.PubID: "301", models.KEY_GEN_PATTERN: "_AU_@_W_x_H_", models.SERVER_SIDE_FLAG: "1", models.VENDORID: "130", @@ -4011,10 +4012,10 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { Reject: false, NbrCode: 0, ChangeSet: hookstage.ChangeSet[hookstage.BeforeValidationRequestPayload]{}, - DebugMessages: []string{`new imp: {"123":{"ImpID":"123","TagID":"adunit","Div":"","SlotName":"adunit","AdUnitName":"adunit","Secure":0,"BidFloor":4.3,"BidFloorCur":"USD","IsRewardInventory":null,"Banner":true,"Video":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"Native":null,"IncomingSlots":["700x900","728x90","300x250","640x480"],"Type":"video","Bidders":{"appnexus":{"PartnerID":2,"PrebidBidderCode":"appnexus","MatchedSlot":"adunit@700x900","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"placementId":0,"site":"12313","adtag":"45343"},"VASTTagFlags":null},"dm-alias":{"PartnerID":3,"PrebidBidderCode":"districtm","MatchedSlot":"adunit@700x900","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"placementId":0,"site":"12313","adtag":"45343"},"VASTTagFlags":null},"pub2-alias":{"PartnerID":1,"PrebidBidderCode":"pubmatic2","MatchedSlot":"adunit@700x900","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"publisherId":"5890","adSlot":"adunit@700x900","wrapper":{"version":1,"profile":1234}},"VASTTagFlags":null}},"NonMapped":{},"NewExt":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"},"dm-alias":{"placementId":0,"site":"12313","adtag":"45343"},"pub2-alias":{"publisherId":"5890","adSlot":"adunit@700x900","wrapper":{"version":1,"profile":1234}}}}},"BidCtx":{},"BannerAdUnitCtx":{"MatchedSlot":"","IsRegex":false,"MatchedRegex":"","SelectedSlotAdUnitConfig":null,"AppliedSlotAdUnitConfig":null,"UsingDefaultConfig":false,"AllowedConnectionTypes":null},"VideoAdUnitCtx":{"MatchedSlot":"","IsRegex":false,"MatchedRegex":"","SelectedSlotAdUnitConfig":null,"AppliedSlotAdUnitConfig":null,"UsingDefaultConfig":false,"AllowedConnectionTypes":null},"BidderError":"","IsAdPodRequest":false,"AdpodConfig":null,"ImpAdPodCfg":null,"BidIDToAPRC":null,"AdserverURL":"","BidIDToDur":null}}`, `new request.ext: {"prebid":{"aliases":{"dm-alias":"appnexus","pub2-alias":"pubmatic"},"aliasgvlids":{"dm-alias":99,"pub2-alias":130},"bidadjustmentfactors":{"appnexus":1,"dm-alias":1,"pub2-alias":1},"bidderparams":{"pub2-alias":{"wiid":""},"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true},"macros":{"[PLATFORM]":"3","[PROFILE_ID]":"1234","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}`}, + DebugMessages: []string{`new imp: {"123":{"ImpID":"123","TagID":"adunit","Div":"","SlotName":"adunit","AdUnitName":"adunit","Secure":0,"BidFloor":4.3,"BidFloorCur":"USD","IsRewardInventory":null,"Banner":true,"Video":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"Native":null,"IncomingSlots":["700x900","728x90","300x250","640x480"],"Type":"video","Bidders":{"appnexus":{"PartnerID":2,"PrebidBidderCode":"appnexus","MatchedSlot":"adunit@700x900","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"placementId":0,"adtag":"45343","site":"12313"},"VASTTagFlags":null},"dm-alias":{"PartnerID":3,"PrebidBidderCode":"districtm","MatchedSlot":"adunit@700x900","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"placementId":0,"site":"12313","adtag":"45343"},"VASTTagFlags":null},"pub2-alias":{"PartnerID":1,"PrebidBidderCode":"pubmatic2","MatchedSlot":"adunit@700x900","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"publisherId":"301","adSlot":"adunit@700x900"},"VASTTagFlags":null}},"NonMapped":{},"NewExt":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"adtag":"45343","site":"12313"},"dm-alias":{"placementId":0,"site":"12313","adtag":"45343"},"pub2-alias":{"publisherId":"301","adSlot":"adunit@700x900"}}}},"BidCtx":{},"BannerAdUnitCtx":{"MatchedSlot":"","IsRegex":false,"MatchedRegex":"","SelectedSlotAdUnitConfig":null,"AppliedSlotAdUnitConfig":null,"UsingDefaultConfig":false,"AllowedConnectionTypes":null},"VideoAdUnitCtx":{"MatchedSlot":"","IsRegex":false,"MatchedRegex":"","SelectedSlotAdUnitConfig":null,"AppliedSlotAdUnitConfig":null,"UsingDefaultConfig":false,"AllowedConnectionTypes":null},"BidderError":"","IsAdPodRequest":false,"AdpodConfig":null,"ImpAdPodCfg":null,"BidIDToAPRC":null,"AdserverURL":"","BidIDToDur":null}}`, `new request.ext: {"prebid":{"aliases":{"dm-alias":"appnexus","pub2-alias":"pubmatic"},"aliasgvlids":{"dm-alias":99,"pub2-alias":130},"bidadjustmentfactors":{"appnexus":1,"dm-alias":1,"pub2-alias":1},"bidderparams":{"pub2-alias":{"wiid":""},"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true},"macros":{"[PLATFORM]":"3","[PROFILE_ID]":"1234","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}`}, AnalyticsTags: hookanalytics.Analytics{}, }, - bidRequest: json.RawMessage(`{"id":"123-456-789","imp":[{"id":"123","banner":{"format":[{"w":728,"h":90},{"w":300,"h":250}],"w":700,"h":900},"video":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"tagid":"adunit","bidfloor":4.3,"bidfloorcur":"USD","ext":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"adtag":"45343","site":"12313"},"dm-alias":{"placementId":0,"site":"12313","adtag":"45343"},"pub2-alias":{"publisherId":"5890","adSlot":"adunit@700x900","wrapper":{"version":1,"profile":1234}}}}}}],"site":{"domain":"test.com","page":"www.test.com","publisher":{"id":"5890"}},"device":{"ua":"Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/52.0.2743.82Safari/537.36","ip":"123.145.167.10"},"user":{"id":"119208432","buyeruid":"1rwe432","yob":1980,"gender":"F","customdata":"7D75D25F-FAC9-443D-B2D1-B17FEE11E027","geo":{"country":"US","region":"CA","metro":"90001","city":"Alamo"}},"wseat":["Wseat_0","Wseat_1"],"bseat":["Bseat_0","Bseat_1"],"cur":["cur_0","cur_1"],"wlang":["Wlang_0","Wlang_1"],"bcat":["bcat_0","bcat_1"],"badv":["badv_0","badv_1"],"bapp":["bapp_0","bapp_1"],"source":{"tid":"123-456-789","ext":{"omidpn":"MyIntegrationPartner","omidpv":"7.1"}},"ext":{"prebid":{"aliases":{"dm-alias":"appnexus","pub2-alias":"pubmatic"},"aliasgvlids":{"dm-alias":99,"pub2-alias":130},"bidadjustmentfactors":{"appnexus":1,"dm-alias":1,"pub2-alias":1},"bidderparams":{"pubmatic":{"wiid":""},"pub2-alias":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true},"macros":{"[PLATFORM]":"3","[PROFILE_ID]":"1234","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}}`), + bidRequest: json.RawMessage(`{"id":"123-456-789","imp":[{"id":"123","banner":{"format":[{"w":728,"h":90},{"w":300,"h":250}],"w":700,"h":900},"video":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"tagid":"adunit","bidfloor":4.3,"bidfloorcur":"USD","ext":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"},"dm-alias":{"placementId":0,"site":"12313","adtag":"45343"},"pub2-alias":{"publisherId":"301","adSlot":"adunit@700x900"}}}}}],"site":{"domain":"test.com","page":"www.test.com","publisher":{"id":"5890"}},"device":{"ua":"Mozilla/5.0(X11;Linuxx86_64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/52.0.2743.82Safari/537.36","ip":"123.145.167.10"},"user":{"id":"119208432","buyeruid":"1rwe432","yob":1980,"gender":"F","customdata":"7D75D25F-FAC9-443D-B2D1-B17FEE11E027","geo":{"country":"US","region":"CA","metro":"90001","city":"Alamo"}},"wseat":["Wseat_0","Wseat_1"],"bseat":["Bseat_0","Bseat_1"],"cur":["cur_0","cur_1"],"wlang":["Wlang_0","Wlang_1"],"bcat":["bcat_0","bcat_1"],"badv":["badv_0","badv_1"],"bapp":["bapp_0","bapp_1"],"source":{"tid":"123-456-789","ext":{"omidpn":"MyIntegrationPartner","omidpv":"7.1"}},"ext":{"prebid":{"aliases":{"dm-alias":"appnexus","pub2-alias":"pubmatic"},"aliasgvlids":{"dm-alias":99,"pub2-alias":130},"bidadjustmentfactors":{"appnexus":1,"dm-alias":1,"pub2-alias":1},"bidderparams":{"pub2-alias":{"wiid":""},"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true},"macros":{"[PLATFORM]":"3","[PROFILE_ID]":"1234","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}}`), error: false, doMutate: true, nilCurrencyConversion: false, diff --git a/modules/pubmatic/openwrap/bidderparams/pubmatic.go b/modules/pubmatic/openwrap/bidderparams/pubmatic.go index e79858bb0d5..9b90a7b2b94 100644 --- a/modules/pubmatic/openwrap/bidderparams/pubmatic.go +++ b/modules/pubmatic/openwrap/bidderparams/pubmatic.go @@ -3,7 +3,6 @@ package bidderparams import ( "encoding/json" "fmt" - "strconv" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/cache" @@ -12,16 +11,9 @@ import ( ) func PreparePubMaticParamsV25(rctx models.RequestCtx, cache cache.Cache, bidRequest openrtb2.BidRequest, imp openrtb2.Imp, impExt models.ImpExtension, partnerID int) (string, string, bool, []byte, error) { - wrapExt := fmt.Sprintf(`{"%s":%d,"%s":%d}`, models.SS_PM_VERSION_ID, rctx.DisplayID, models.SS_PM_PROFILE_ID, rctx.ProfileID) - - // change profile id for pubmatic2 - if secondaryProfileID, ok := rctx.PartnerConfigMap[partnerID][models.KEY_PROFILE_ID]; ok { - wrapExt = fmt.Sprintf(`{"%s":0,"%s":%s}`, models.SS_PM_VERSION_ID, models.SS_PM_PROFILE_ID, secondaryProfileID) - } - extImpPubMatic := openrtb_ext.ExtImpPubmatic{ - PublisherId: strconv.Itoa(rctx.PubID), - WrapExt: json.RawMessage(wrapExt), + PublisherId: getPubMaticPublisherID(rctx, partnerID), + WrapExt: getPubMaticWrapperExt(rctx, partnerID), Keywords: getImpExtPubMaticKeyWords(impExt, rctx.PartnerConfigMap[partnerID][models.BidderCode]), Floors: getApplovinBidFloors(rctx, imp), SendBurl: rctx.SendBurl, @@ -149,3 +141,33 @@ func getMatchingSlotAndPattern(rctx models.RequestCtx, cache cache.Cache, slots } return matchedSlot, matchedPattern, isRegexSlot } + +func getPubMaticPublisherID(rctx models.RequestCtx, partnerID int) string { + //Pubmatic secondary flow send account level pubID + if pubID, ok := rctx.PartnerConfigMap[partnerID][models.KEY_PUBLISHER_ID]; ok { + return pubID + } + //PubMatic alias flow + if pubID, ok := rctx.PartnerConfigMap[partnerID][models.PubID]; ok { + return pubID + } + //PubMatic primary flow + return rctx.PubIDStr +} + +func getPubMaticWrapperExt(rctx models.RequestCtx, partnerID int) json.RawMessage { + wrapExt := fmt.Sprintf(`{"%s":%d,"%s":%d}`, models.SS_PM_VERSION_ID, rctx.DisplayID, models.SS_PM_PROFILE_ID, rctx.ProfileID) + + // change profile id for pubmatic2 + if secondaryProfileID, ok := rctx.PartnerConfigMap[partnerID][models.KEY_PROFILE_ID]; ok { + wrapExt = fmt.Sprintf(`{"%s":%s}`, models.SS_PM_PROFILE_ID, secondaryProfileID) + } + + //Pubmatic alias flow do not send wrapExt + if isAlias, ok := rctx.PartnerConfigMap[partnerID][models.IsAlias]; ok && isAlias == "1" { + if pubID, ok := rctx.PartnerConfigMap[partnerID][models.PubID]; ok && pubID != rctx.PubIDStr { + return nil + } + } + return json.RawMessage(wrapExt) +} diff --git a/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go b/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go index 1efdf6150e4..604a7c6e40c 100644 --- a/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go +++ b/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go @@ -1,6 +1,7 @@ package bidderparams import ( + "encoding/json" "testing" "github.com/golang/mock/gomock" @@ -254,6 +255,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 1, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -320,23 +322,25 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ 1: { - models.PREBID_PARTNER_NAME: "pubmatic", - models.BidderCode: "pubmatic", + models.PREBID_PARTNER_NAME: "pubmatic2", + models.BidderCode: "pubmatic2", models.TIMEOUT: "200", models.KEY_GEN_PATTERN: "_AU_@_DIV_@_W_x_H_", models.SERVER_SIDE_FLAG: "1", models.KEY_PROFILE_ID: "1323", + models.KEY_PUBLISHER_ID: "301", }, }, }, cache: mockCache, impExt: models.ImpExtension{ Bidder: map[string]*models.BidderExtension{ - "pubmatic": { + "pubmatic2": { KeyWords: []models.KeyVal{ { Key: "test_key1", @@ -377,7 +381,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { matchedSlot: "/Test_Adunit1234@Div1@200x300", matchedPattern: "", isRegexSlot: false, - params: []byte(`{"publisherId":"5890","adSlot":"/Test_Adunit1234@DIV1@200x300","wrapper":{"version":0,"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + params: []byte(`{"publisherId":"301","adSlot":"/Test_Adunit1234@DIV1@200x300","wrapper":{"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), wantErr: false, }, }, @@ -387,23 +391,91 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ 1: { - models.PREBID_PARTNER_NAME: "pubmatic", - models.BidderCode: "pubmatic", + models.PREBID_PARTNER_NAME: "pubmatic2", + models.BidderCode: "pubmatic2", models.TIMEOUT: "200", models.KEY_GEN_PATTERN: "_RE_@_W_x_H_", models.SERVER_SIDE_FLAG: "1", models.KEY_PROFILE_ID: "1323", + models.KEY_PUBLISHER_ID: "301", }, }, }, cache: mockCache, impExt: models.ImpExtension{ Bidder: map[string]*models.BidderExtension{ - "pubmatic": { + "pubmatic2": { + KeyWords: []models.KeyVal{ + { + Key: "test_key1", + Values: []string{"test_value1", "test_value2"}, + }, + { + Key: "test_key2", + Values: []string{"test_value1", "test_value2"}, + }, + }, + }, + }, + }, + imp: getTestImp("/Test_Adunit1234", true, false), + partnerID: 1, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + "/test_adunit1234@200x300": { + PartnerId: 1, + AdapterId: 1, + SlotName: "/Test_Adunit1234@200x300", + SlotMappings: map[string]interface{}{ + "site": "12313", + "adtag": "45343", + "slotName": "/Test_Adunit1234@200x300", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"test", "test1"}, + }) + }, + want: want{ + matchedSlot: "/Test_Adunit1234@200x300", + matchedPattern: "", + isRegexSlot: false, + params: []byte(`{"publisherId":"301","adSlot":"/Test_Adunit1234@200x300","wrapper":{"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + wantErr: false, + }, + }, + { + name: "exact_matched_slot_found_adslot_updated_from_PubMatic_alias_flow_for_prebids2s_regex", + args: args{ + rctx: models.RequestCtx{ + IsTestRequest: 0, + PubID: 5890, + PubIDStr: "5890", + ProfileID: 123, + DisplayID: 1, + PartnerConfigMap: map[int]map[string]string{ + 1: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubmatic_alias", + models.TIMEOUT: "200", + models.KEY_GEN_PATTERN: "_RE_@_W_x_H_", + models.SERVER_SIDE_FLAG: "1", + models.IsAlias: "1", + models.PubID: "301", + }, + }, + }, + cache: mockCache, + impExt: models.ImpExtension{ + Bidder: map[string]*models.BidderExtension{ + "pubmatic_alias": { KeyWords: []models.KeyVal{ { Key: "test_key1", @@ -441,7 +513,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { matchedSlot: "/Test_Adunit1234@200x300", matchedPattern: "", isRegexSlot: false, - params: []byte(`{"publisherId":"5890","adSlot":"/Test_Adunit1234@200x300","wrapper":{"version":0,"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + params: []byte(`{"publisherId":"301","adSlot":"/Test_Adunit1234@200x300","keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), wantErr: false, }, }, @@ -451,6 +523,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -514,6 +587,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -583,6 +657,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -649,6 +724,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -721,6 +797,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -787,6 +864,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -853,6 +931,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -919,6 +998,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -985,6 +1065,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -1051,6 +1132,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 1, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -1122,6 +1204,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 2, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -1171,6 +1254,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 2, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, DisplayID: 1, PartnerConfigMap: map[int]map[string]string{ @@ -1220,6 +1304,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { rctx: models.RequestCtx{ IsTestRequest: 0, PubID: 5890, + PubIDStr: "5890", ProfileID: 123, ProfileIDStr: "123", DisplayID: 1, @@ -1231,7 +1316,6 @@ func TestPreparePubMaticParamsV25(t *testing.T) { models.TIMEOUT: "200", models.KEY_GEN_PATTERN: "_AU_@_DIV_@_W_x_H_", models.SERVER_SIDE_FLAG: "1", - models.KEY_PROFILE_ID: "1323", }, }, AppLovinMax: models.AppLovinMax{ @@ -1288,7 +1372,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { matchedSlot: "/Test_Adunit1234@Div1@200x300", matchedPattern: "", isRegexSlot: false, - params: []byte(`{"publisherId":"5890","adSlot":"/Test_Adunit1234@DIV1@200x300","wrapper":{"version":0,"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}],"floors":[1.5,1.2,2.2],"sendburl":true}`), + params: []byte(`{"publisherId":"5890","adSlot":"/Test_Adunit1234@DIV1@200x300","wrapper":{"version":1,"profile":123},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}],"floors":[1.5,1.2,2.2],"sendburl":true}`), wantErr: false, }, }, @@ -1437,3 +1521,196 @@ func TestGetMatchingSlotAndPattern(t *testing.T) { }) } } + +func TestGetPubMaticPublisherID(t *testing.T) { + type args struct { + rctx models.RequestCtx + partnerID int + } + tests := []struct { + name string + args args + want string + }{ + { + name: "pubmatic partner", + args: args{ + partnerID: 789, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 789: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubmatic", + models.PubID: "5890", + }, + }, + PubID: 5890, + PubIDStr: "5890", + }, + }, + want: "5890", + }, + { + name: "pubmatic secondary partner", + args: args{ + partnerID: 123, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 123: { + models.PREBID_PARTNER_NAME: "pubmatic2", + models.BidderCode: "pubmatic2", + models.KEY_PUBLISHER_ID: "301", + models.PubID: "5890", + }, + }, + PubID: 5890, + PubIDStr: "5890", + }, + }, + want: "301", + }, + { + name: "pubmatic alias partner", + args: args{ + partnerID: 456, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 456: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubm_alias", + models.PubID: "301", + models.IsAlias: "1", + }, + }, + PubID: 5890, + PubIDStr: "5890", + }, + }, + want: "301", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := getPubMaticPublisherID(tt.args.rctx, tt.args.partnerID) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestGetPubMaticWrapperExt(t *testing.T) { + type args struct { + rctx models.RequestCtx + partnerID int + } + tests := []struct { + name string + args args + want json.RawMessage + }{ + { + name: "pubmatic partner", + args: args{ + partnerID: 789, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 789: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubmatic", + models.PubID: "5890", + }, + }, + DisplayID: 1, + ProfileID: 1234, + PubID: 5890, + }, + }, + want: json.RawMessage(`{"version":1,"profile":1234}`), + }, + { + name: "pubmatic secondary partner", + args: args{ + partnerID: 123, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 123: { + models.PREBID_PARTNER_NAME: "pubmatic2", + models.BidderCode: "pubmatic2", + models.KEY_PROFILE_ID: "222", + }, + }, + DisplayID: 1, + ProfileID: 1234, + }, + }, + want: json.RawMessage(`{"profile":222}`), + }, + { + name: "pubmatic alias partner with pubID different from incoming request pubID", + args: args{ + partnerID: 456, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 456: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubm_alias", + models.PubID: "301", + models.IsAlias: "1", + }, + }, + DisplayID: 1, + ProfileID: 1234, + PubID: 5890, + PubIDStr: "5890", + }, + }, + want: nil, + }, + { + name: "pubmatic alias partner with pubID same as incoming request pubID", + args: args{ + partnerID: 456, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 456: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubm_alias", + models.PubID: "5890", + models.IsAlias: "1", + }, + }, + DisplayID: 1, + ProfileID: 1234, + PubID: 5890, + PubIDStr: "5890", + }, + }, + want: json.RawMessage(`{"version":1,"profile":1234}`), + }, + { + name: "pubmatic alias partner with no pubID in partner config", + args: args{ + partnerID: 456, + rctx: models.RequestCtx{ + PartnerConfigMap: map[int]map[string]string{ + 456: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubm_alias", + models.IsAlias: "1", + }, + }, + DisplayID: 1, + ProfileID: 1234, + PubID: 5890, + PubIDStr: "5890", + }, + }, + want: json.RawMessage(`{"version":1,"profile":1234}`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := getPubMaticWrapperExt(tt.args.rctx, tt.args.partnerID) + assert.Equal(t, tt.want, got) + }) + } +} From 8a1de80db89831301a0bd5ef161920b969287037 Mon Sep 17 00:00:00 2001 From: pm-priyanka-bagade <156899734+pm-priyanka-bagade@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:19:21 +0530 Subject: [PATCH 02/24] UOE-10950 : kgpv and kgpsv getting empty in logger for flag test=1 (#877) * updated kgpv for regex * added test cases * resolved comments * added test cases * changed adslot logic for testvalue=2 * check for empty kgpv in logger * resolved review comments --- .../openwrap/bidderparams/pubmatic.go | 8 +- .../openwrap/bidderparams/pubmatic_test.go | 297 +++++++++++++++++- .../pubmatic/openwrap/models/utils_test.go | 34 +- 3 files changed, 303 insertions(+), 36 deletions(-) diff --git a/modules/pubmatic/openwrap/bidderparams/pubmatic.go b/modules/pubmatic/openwrap/bidderparams/pubmatic.go index 9b90a7b2b94..e1583092c34 100644 --- a/modules/pubmatic/openwrap/bidderparams/pubmatic.go +++ b/modules/pubmatic/openwrap/bidderparams/pubmatic.go @@ -30,13 +30,7 @@ func PreparePubMaticParamsV25(rctx models.RequestCtx, cache cache.Cache, bidRequ isRegexKGP = true } - if rctx.IsTestRequest == 1 { - matchedSlot, matchedPattern, isRegexSlot = getMatchingSlotAndPattern(rctx, cache, slots, slotMap, slotMappingInfo, isRegexKGP, isRegexSlot, partnerID, &extImpPubMatic, imp) - params, err := json.Marshal(extImpPubMatic) - return matchedSlot, matchedPattern, isRegexSlot, params, err - } - - if rctx.IsTestRequest > 0 { + if rctx.IsTestRequest == models.TestValueTwo { if len(slots) > 0 { extImpPubMatic.AdSlot = slots[0] } diff --git a/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go b/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go index 604a7c6e40c..14b004fd4f1 100644 --- a/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go +++ b/modules/pubmatic/openwrap/bidderparams/pubmatic_test.go @@ -293,26 +293,31 @@ func TestPreparePubMaticParamsV25(t *testing.T) { }, setup: func() { mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ - "/test_adunit1234@div1@200x300": { + "/test_adunit12345@div1@200x300": { PartnerId: 1, AdapterId: 1, SlotName: "/Test_Adunit1234@Div1@200x300", SlotMappings: map[string]interface{}{ "site": "12313", "adtag": "45343", - "slotName": "/Test_Adunit1234@DIV1@200x300", + "slotName": "/Test_Adunit1234@Div1@200x300", }, }, }) mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ - OrderedSlotList: []string{"test", "test1"}, + OrderedSlotList: []string{"/test_adunit1234@div1@200x300"}, + HashValueMap: map[string]string{ + "/test_adunit1234@div1@200x300": "2aa34b52a9e941c1594af7565e599c8d", + }, }) + mockCache.EXPECT().Get("psregex_5890_123_1_1_/Test_Adunit1234@Div1@200x300").Return(nil, false) + mockCache.EXPECT().Set("psregex_5890_123_1_1_/Test_Adunit1234@Div1@200x300", regexSlotEntry{SlotName: "/Test_Adunit1234@Div1@200x300", RegexPattern: "/test_adunit1234@div1@200x300"}).Times(1) }, want: want{ matchedSlot: "/Test_Adunit1234@Div1@200x300", - matchedPattern: "", - isRegexSlot: false, - params: []byte(`{"publisherId":"5890","adSlot":"/Test_Adunit1234@Div1@200x300","wrapper":{"version":1,"profile":123},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + matchedPattern: "/test_adunit1234@div1@200x300", + isRegexSlot: true, + params: []byte(`{"publisherId":"5890","adSlot":"2aa34b52a9e941c1594af7565e599c8d","wrapper":{"version":1,"profile":123},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), wantErr: false, }, }, @@ -791,6 +796,79 @@ func TestPreparePubMaticParamsV25(t *testing.T) { wantErr: false, }, }, + { + name: "regex_matched_slot_found_adSlot_upadted_from_hashValue_for_test_value_1", + args: args{ + rctx: models.RequestCtx{ + IsTestRequest: 1, + PubID: 5890, + PubIDStr: "5890", + ProfileID: 123, + DisplayID: 1, + PartnerConfigMap: map[int]map[string]string{ + 1: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubmatic", + models.TIMEOUT: "200", + models.KEY_GEN_PATTERN: "_AU_@_DIV_@_W_x_H_", + models.SERVER_SIDE_FLAG: "1", + }, + }, + }, + cache: mockCache, + impExt: models.ImpExtension{ + Bidder: map[string]*models.BidderExtension{ + "pubmatic": { + KeyWords: []models.KeyVal{ + { + Key: "test_key1", + Values: []string{"test_value1", "test_value2"}, + }, + { + Key: "test_key2", + Values: []string{"test_value1", "test_value2"}, + }, + }, + }, + }, + Wrapper: &models.ExtImpWrapper{ + Div: "Div1", + }, + }, + imp: getTestImp("/Test_Adunit1234", true, false), + partnerID: 1, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + ".*@div.*@.*": { + PartnerId: 1, + AdapterId: 1, + SlotName: "/Test_Adunit1234@Div1@200x300", + SlotMappings: map[string]interface{}{ + "site": "12313", + "adtag": "45343", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"test", "test1"}, + HashValueMap: map[string]string{ + ".*@Div.*@.*": "2aa34b52a9e941c1594af7565e599c8d", + }, + }) + mockCache.EXPECT().Get("psregex_5890_123_1_1_/Test_Adunit1234@Div1@200x300").Return(regexSlotEntry{ + SlotName: "/Test_Adunit1234@Div1@200x300", + RegexPattern: ".*@Div.*@.*", + }, true) + }, + want: want{ + matchedSlot: "/Test_Adunit1234@Div1@200x300", + matchedPattern: ".*@Div.*@.*", + isRegexSlot: true, + params: []byte(`{"publisherId":"5890","adSlot":"2aa34b52a9e941c1594af7565e599c8d","wrapper":{"version":1,"profile":123},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + wantErr: false, + }, + }, { name: "valid_pubmatic_native_params", args: args{ @@ -1127,7 +1205,7 @@ func TestPreparePubMaticParamsV25(t *testing.T) { }, }, { - name: "For test value 1", + name: "For_test_value_1_for_regex", args: args{ rctx: models.RequestCtx{ IsTestRequest: 1, @@ -1198,6 +1276,211 @@ func TestPreparePubMaticParamsV25(t *testing.T) { wantErr: false, }, }, + { + name: "For_test_value_1_for_non_regex", + args: args{ + rctx: models.RequestCtx{ + IsTestRequest: 1, + PubID: 5890, + PubIDStr: "5890", + ProfileID: 123, + DisplayID: 1, + PartnerConfigMap: map[int]map[string]string{ + 1: { + models.PREBID_PARTNER_NAME: "pubmatic", + models.BidderCode: "pubmatic", + models.TIMEOUT: "200", + models.KEY_GEN_PATTERN: "_AU_@_W_x_H_", + models.SERVER_SIDE_FLAG: "1", + }, + }, + }, + cache: mockCache, + impExt: models.ImpExtension{ + Bidder: map[string]*models.BidderExtension{ + "pubmatic": { + KeyWords: []models.KeyVal{ + { + Key: "test_key1", + Values: []string{"test_value1", "test_value2"}, + }, + { + Key: "test_key2", + Values: []string{"test_value1", "test_value2"}, + }, + }, + }, + }, + Wrapper: &models.ExtImpWrapper{ + Div: "Div1", + }, + }, + imp: getTestImp("/Test_Adunit1234", false, false), + partnerID: 1, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + "/test_adunit1234@1x1": { + PartnerId: 1, + AdapterId: 1, + SlotName: "/Test_Adunit1234@1x1", + SlotMappings: map[string]interface{}{ + "site": "12313", + "adtag": "45343", + models.KEY_OW_SLOT_NAME: "/Test_Adunit1234@1x1", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"test", "test1"}, + }) + }, + want: want{ + matchedSlot: "/Test_Adunit1234@1x1", + matchedPattern: "", + isRegexSlot: false, + params: []byte(`{"publisherId":"5890","adSlot":"/Test_Adunit1234@1x1","wrapper":{"version":1,"profile":123},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + wantErr: false, + }, + }, + { + name: "For_test_value_1_exact_matched_slot_found_adslot_updated_from_PubMatic_secondary_flow", + args: args{ + rctx: models.RequestCtx{ + IsTestRequest: 1, + PubID: 5890, + PubIDStr: "5890", + ProfileID: 123, + DisplayID: 1, + PartnerConfigMap: map[int]map[string]string{ + 1: { + models.PREBID_PARTNER_NAME: "pubmatic2", + models.BidderCode: "pubmatic2", + models.TIMEOUT: "200", + models.KEY_GEN_PATTERN: "_AU_@_DIV_@_W_x_H_", + models.SERVER_SIDE_FLAG: "1", + models.KEY_PROFILE_ID: "1323", + models.KEY_PUBLISHER_ID: "301", + }, + }, + }, + cache: mockCache, + impExt: models.ImpExtension{ + Bidder: map[string]*models.BidderExtension{ + "pubmatic2": { + KeyWords: []models.KeyVal{ + { + Key: "test_key1", + Values: []string{"test_value1", "test_value2"}, + }, + { + Key: "test_key2", + Values: []string{"test_value1", "test_value2"}, + }, + }, + }, + }, + Wrapper: &models.ExtImpWrapper{ + Div: "Div1", + }, + }, + imp: getTestImp("/Test_Adunit1234", true, false), + partnerID: 1, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + "/test_adunit1234@div1@200x300": { + PartnerId: 1, + AdapterId: 1, + SlotName: "/Test_Adunit1234@Div1@200x300", + SlotMappings: map[string]interface{}{ + "site": "12313", + "adtag": "45343", + "slotName": "/Test_Adunit1234@DIV1@200x300", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"test", "test1"}, + }) + }, + want: want{ + matchedSlot: "/Test_Adunit1234@Div1@200x300", + matchedPattern: "", + isRegexSlot: false, + params: []byte(`{"publisherId":"301","adSlot":"/Test_Adunit1234@DIV1@200x300","wrapper":{"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + wantErr: false, + }, + }, + { + name: "For_test_value_1_exact_matched_slot_found_adslot_updated_from_PubMatic_secondary_flow_for_different_slotname", + args: args{ + rctx: models.RequestCtx{ + IsTestRequest: 1, + PubID: 5890, + PubIDStr: "5890", + ProfileID: 123, + DisplayID: 1, + PartnerConfigMap: map[int]map[string]string{ + 1: { + models.PREBID_PARTNER_NAME: "pubmatic2", + models.BidderCode: "pubmatic2", + models.TIMEOUT: "200", + models.KEY_GEN_PATTERN: "_AU_@_DIV_@_W_x_H_", + models.SERVER_SIDE_FLAG: "1", + models.KEY_PROFILE_ID: "1323", + models.KEY_PUBLISHER_ID: "301", + }, + }, + }, + cache: mockCache, + impExt: models.ImpExtension{ + Bidder: map[string]*models.BidderExtension{ + "pubmatic2": { + KeyWords: []models.KeyVal{ + { + Key: "test_key1", + Values: []string{"test_value1", "test_value2"}, + }, + { + Key: "test_key2", + Values: []string{"test_value1", "test_value2"}, + }, + }, + }, + }, + Wrapper: &models.ExtImpWrapper{ + Div: "Div1", + }, + }, + imp: getTestImp("/Test_Adunit1234", true, false), + partnerID: 1, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + "/test_adunit1234@div1@200x300": { + PartnerId: 1, + AdapterId: 1, + SlotName: "/Test_Adunit1234@Div1@200x300", + SlotMappings: map[string]interface{}{ + "site": "12313", + "adtag": "45343", + "slotName": "pubmatic2-slot", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"test", "test1"}, + }) + }, + want: want{ + matchedSlot: "/Test_Adunit1234@Div1@200x300", + matchedPattern: "", + isRegexSlot: false, + params: []byte(`{"publisherId":"301","adSlot":"pubmatic2-slot","wrapper":{"profile":1323},"keywords":[{"key":"test_key1","value":["test_value1","test_value2"]},{"key":"test_key2","value":["test_value1","test_value2"]}]}`), + wantErr: false, + }, + }, { name: "For_test_value_2_with_regex", args: args{ diff --git a/modules/pubmatic/openwrap/models/utils_test.go b/modules/pubmatic/openwrap/models/utils_test.go index 5e878cfaf19..afff46c2bf4 100644 --- a/modules/pubmatic/openwrap/models/utils_test.go +++ b/modules/pubmatic/openwrap/models/utils_test.go @@ -1229,6 +1229,7 @@ func TestGetKGPSV(t *testing.T) { args: args{ bidderMeta: PartnerData{ KGPV: "kgpv", + KGP: "_AU_@_W_x_H_", }, }, kgpv: "kgpv", @@ -1240,6 +1241,7 @@ func TestGetKGPSV(t *testing.T) { bidderMeta: PartnerData{ KGPV: "kgpv", IsRegex: true, + KGP: "_AU_@_DIV_@_W_x_H_", }, }, kgpv: "kgpv", @@ -1251,6 +1253,7 @@ func TestGetKGPSV(t *testing.T) { bidderMeta: PartnerData{ MatchedSlot: "kgpsv", IsRegex: true, + KGP: "_AU_@_DIV_@_W_x_H_", }, }, kgpv: "kgpsv", @@ -1269,6 +1272,7 @@ func TestGetKGPSV(t *testing.T) { KGPV: "kgpv", MatchedSlot: "kgpsv", IsRegex: true, + KGP: "_AU_@_DIV_@_W_x_H_", }, }, kgpv: "kgpv", @@ -1287,27 +1291,14 @@ func TestGetKGPSV(t *testing.T) { KGPV: "kgpv", MatchedSlot: "kgpsv", IsRegex: false, + KGP: "_AU_@_W_x_H_", }, }, kgpv: "kgpv", kgpsv: "kgpv", }, { - name: "KGPV and KGP not present in partnerData,regex false and adformat is video", - args: args{ - bid: openrtb2.Bid{ - Price: 1, - DealID: "deal", - W: 250, - H: 300, - }, - adformat: Video, - }, - kgpv: "", - kgpsv: "", - }, - { - name: "KGPV not present in partnerData,regex false and adformat is video", + name: "KGPV not present in partnerData, regex false and adformat is video", args: args{ bid: openrtb2.Bid{ Price: 1, @@ -1325,7 +1316,7 @@ func TestGetKGPSV(t *testing.T) { kgpsv: "adunit@0x0", }, { - name: "KGPV not present in partnerData,regex false and adformat is banner", + name: "KGPV not present in partnerData, regex false and adformat is banner", args: args{ bid: openrtb2.Bid{ Price: 1, @@ -1347,12 +1338,11 @@ func TestGetKGPSV(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, got1 := GetKGPSV(tt.args.bid, tt.args.bidExt, tt.args.bidderMeta, tt.args.adformat, tt.args.tagId, tt.args.div, tt.args.source) - if got != tt.kgpv { - t.Errorf("GetKGPSV() got = %v, want %v", got, tt.kgpv) - } - if got1 != tt.kgpsv { - t.Errorf("GetKGPSV() got1 = %v, want %v", got1, tt.kgpsv) - } + + // Ensure KGPV is not empty + assert.NotEmpty(t, got, "KGPV should not be empty") + assert.Equal(t, tt.kgpv, got, "GetKGPSV() got = %v, want %v", got, tt.kgpv) + assert.Equal(t, tt.kgpsv, got1, "GetKGPSV() got1 = %v, want %v", got1, tt.kgpsv) }) } } From 3334b0f76a38a93fe0349359c5c7674700cc9dd4 Mon Sep 17 00:00:00 2001 From: ashishshinde-pubm <109787960+ashishshinde-pubm@users.noreply.github.com> Date: Mon, 2 Sep 2024 11:19:48 +0530 Subject: [PATCH 03/24] OTT-1807: discard emptyVAST and invalidVAST bids detected by VAST unwrap module (#874) * OTT-1807: discard emptyVAST and invalidVAST bids --- analytics/pubmatic/logger.go | 31 + analytics/pubmatic/logger_test.go | 708 ++++++++++++++---- go.mod | 3 +- go.sum | 4 +- hooks/hookexecution/executor.go | 4 +- hooks/hookexecution/mocks_test.go | 4 +- hooks/hookstage/rawbidderresponse.go | 4 +- .../hookstage/rawbidderresponse_mutations.go | 2 +- .../ortb2blocking/hook_raw_bidder_response.go | 4 +- modules/prebid/ortb2blocking/module_test.go | 308 ++++---- modules/pubmatic/openwrap/config/config.go | 1 - .../openwrap/hook_raw_bidder_response.go | 90 ++- .../openwrap/hook_raw_bidder_response_test.go | 506 ++++++++----- modules/pubmatic/openwrap/models/constants.go | 32 +- modules/pubmatic/openwrap/models/nbr/codes.go | 1 + modules/pubmatic/openwrap/unwrap/unwrap.go | 19 +- .../pubmatic/openwrap/unwrap/unwrap_test.go | 94 ++- 17 files changed, 1245 insertions(+), 570 deletions(-) diff --git a/analytics/pubmatic/logger.go b/analytics/pubmatic/logger.go index 597c4320801..9a55f4a685e 100644 --- a/analytics/pubmatic/logger.go +++ b/analytics/pubmatic/logger.go @@ -383,6 +383,8 @@ func getPartnerRecordsByImp(ao analytics.AuctionObject, rCtx *models.RequestCtx) } price := bid.Price + // If bids are rejected before setting bidExt.OriginalBidCPM, calculate the price and ocpm values based on the currency and revshare. + price = computeBidPriceForBidsRejectedBeforeSettingOCPM(rCtx, &bidExt, price, revShare, ao) if ao.Response.Cur != models.USD { if bidCtx.EN != 0 { // valid-bids + dropped-bids+ default-bids price = bidCtx.EN @@ -564,3 +566,32 @@ func getAdPodSlot(adPodConfig *models.AdPod) *AdPodSlot { return &adPodSlot } + +func GetBidPriceAfterCurrencyConversion(price float64, requestCurrencies []string, responseCurrency string, + currencyConverter func(fromCurrency string, toCurrency string, value float64) (float64, error)) float64 { + if len(requestCurrencies) == 0 { + requestCurrencies = []string{models.USD} + } + for _, requestCurrency := range requestCurrencies { + if value, err := currencyConverter(responseCurrency, requestCurrency, price); err == nil { + return value + } + } + return 0 // in case of error, send 0 value to make it consistent with prebid +} + +func computeBidPriceForBidsRejectedBeforeSettingOCPM(rCtx *models.RequestCtx, bidExt *models.BidExt, + price, revshare float64, ao analytics.AuctionObject) float64 { + if price != 0 && bidExt.OriginalBidCPM == 0 { + if len(bidExt.OriginalBidCur) == 0 { + bidExt.OriginalBidCur = models.USD + } + bidExt.OriginalBidCPM = price + price = price * models.GetBidAdjustmentValue(revshare) + if cpmUSD, err := rCtx.CurrencyConversion(bidExt.OriginalBidCur, models.USD, price); err == nil { + bidExt.OriginalBidCPMUSD = cpmUSD + } + price = GetBidPriceAfterCurrencyConversion(price, ao.RequestWrapper.Cur, bidExt.OriginalBidCur, rCtx.CurrencyConversion) + } + return price +} diff --git a/analytics/pubmatic/logger_test.go b/analytics/pubmatic/logger_test.go index b01f1f7b501..b12bdc8a9bc 100644 --- a/analytics/pubmatic/logger_test.go +++ b/analytics/pubmatic/logger_test.go @@ -2,6 +2,7 @@ package pubmatic import ( "encoding/json" + "fmt" "net/http" "net/url" "testing" @@ -294,7 +295,8 @@ func TestGetPartnerRecordsByImp(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -347,7 +349,8 @@ func TestGetPartnerRecordsByImp(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -403,7 +406,8 @@ func TestGetPartnerRecordsByImp(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -459,7 +463,8 @@ func TestGetPartnerRecordsByImp(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -512,7 +517,8 @@ func TestGetPartnerRecordsByImp(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -564,7 +570,8 @@ func TestGetPartnerRecordsByImp(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -709,7 +716,8 @@ func TestGetPartnerRecordsByImpForTracker(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, + ExtBid: openrtb_ext.ExtBid{}, }, }, }, @@ -771,6 +779,7 @@ func TestGetPartnerRecordsByImpForTracker(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ + OriginalBidCPM: 12, ExtBid: openrtb_ext.ExtBid{ Prebid: &openrtb_ext.ExtBidPrebid{ Floors: &openrtb_ext.ExtBidPrebidFloors{ @@ -1015,7 +1024,8 @@ func TestGetPartnerRecordsByImpForDefaultBids(t *testing.T) { BidCtx: map[string]models.BidCtx{ "bid-id-1": { BidExt: models.BidExt{ - ExtBid: openrtb_ext.ExtBid{}, + ExtBid: openrtb_ext.ExtBid{}, + OriginalBidCPM: 10, }, }, }, @@ -1420,6 +1430,297 @@ func TestGetPartnerRecordsByImpForSeatNonBid(t *testing.T) { }, }, }, + { + name: "log rejected non-bid having bidder_response_currency EUR and request_currency USD", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Cur: []string{models.USD}, + }, + }, + Response: &openrtb2.BidResponse{Cur: models.USD}, + SeatNonBid: []openrtb_ext.SeatNonBid{ + { + Seat: "appnexus", + NonBid: []openrtb_ext.NonBid{ + { + ImpId: "imp1", + StatusCode: int(nbr.LossBidLostInVastUnwrap), + Ext: openrtb_ext.ExtNonBid{ + Prebid: openrtb_ext.ExtNonBidPrebid{ + Bid: openrtb_ext.ExtNonBidPrebidBid{ + Price: 10, + ID: "bid-id-1", + W: 10, + H: 50, + OriginalBidCur: "EUR", + }, + }, + }, + }, + }, + }, + }, + }, + rCtx: &models.RequestCtx{ + CurrencyConversion: func(from, to string, value float64) (float64, error) { + if from == "USD" && to == "EUR" { + return value * 1.2, nil + } + if from == "EUR" && to == "USD" { + return value * 0.8, nil + } + return 0, nil + }, + ImpBidCtx: map[string]models.ImpCtx{ + "imp1": { + Bidders: map[string]models.PartnerData{ + "appnexus": { + PartnerID: 1, + PrebidBidderCode: "appnexus", + KGP: "kgp", + KGPV: "kgpv", + }, + }, + BidCtx: map[string]models.BidCtx{ + "bid-id-1": { + BidExt: models.BidExt{ + ExtBid: openrtb_ext.ExtBid{}, + Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), + }, + }, + }, + BidFloor: 10.5, + BidFloorCur: "USD", + }, + }, + PartnerConfigMap: map[int]map[string]string{ + 1: { + "rev_share": "0", + }, + }, + WinningBids: make(models.WinningBids), + Platform: models.PLATFORM_APP, + }, + }, + partners: map[string][]PartnerRecord{ + "imp1": { + { + PartnerID: "appnexus", + BidderCode: "appnexus", + KGPV: "kgpv", + KGPSV: "kgpv", + PartnerSize: "10x50", + GrossECPM: 8, + NetECPM: 8, + BidID: "bid-id-1", + OrigBidID: "bid-id-1", + DealID: "-1", + ServerSide: 1, + OriginalCPM: 10, + OriginalCur: "EUR", + FloorValue: 10.5, + FloorRuleValue: 10.5, + Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), + }, + }, + }, + }, + { + name: "log rejected non-bid having bidder_response_currency EUR and request_currency USD and having 50% revshare", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Cur: []string{models.USD}, + }, + }, + Response: &openrtb2.BidResponse{Cur: models.USD}, + SeatNonBid: []openrtb_ext.SeatNonBid{ + { + Seat: "appnexus", + NonBid: []openrtb_ext.NonBid{ + { + ImpId: "imp1", + StatusCode: int(nbr.LossBidLostInVastUnwrap), + Ext: openrtb_ext.ExtNonBid{ + Prebid: openrtb_ext.ExtNonBidPrebid{ + Bid: openrtb_ext.ExtNonBidPrebidBid{ + Price: 10, + ID: "bid-id-1", + W: 10, + H: 50, + OriginalBidCur: "EUR", + }, + }, + }, + }, + }, + }, + }, + }, + rCtx: &models.RequestCtx{ + CurrencyConversion: func(from, to string, value float64) (float64, error) { + if from == "USD" && to == "EUR" { + return value * 1.2, nil + } + if from == "EUR" && to == "USD" { + return value * 0.8, nil + } + return 0, nil + }, + ImpBidCtx: map[string]models.ImpCtx{ + "imp1": { + Bidders: map[string]models.PartnerData{ + "appnexus": { + PartnerID: 1, + PrebidBidderCode: "appnexus", + KGP: "kgp", + KGPV: "kgpv", + }, + }, + BidCtx: map[string]models.BidCtx{ + "bid-id-1": { + BidExt: models.BidExt{ + ExtBid: openrtb_ext.ExtBid{}, + Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), + }, + }, + }, + BidFloor: 10.5, + BidFloorCur: "USD", + }, + }, + PartnerConfigMap: map[int]map[string]string{ + 1: { + "rev_share": "50", + }, + }, + WinningBids: make(models.WinningBids), + Platform: models.PLATFORM_APP, + }, + }, + partners: map[string][]PartnerRecord{ + "imp1": { + { + PartnerID: "appnexus", + BidderCode: "appnexus", + KGPV: "kgpv", + KGPSV: "kgpv", + PartnerSize: "10x50", + GrossECPM: 8, + NetECPM: 4, + BidID: "bid-id-1", + OrigBidID: "bid-id-1", + DealID: "-1", + ServerSide: 1, + OriginalCPM: 10, + OriginalCur: "EUR", + FloorValue: 10.5, + FloorRuleValue: 10.5, + Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), + }, + }, + }, + }, + { + name: "log rejected non-bid having response_currency USD and request_currency EUR and having 50% revshare", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Cur: []string{"EUR"}, + }, + }, + Response: &openrtb2.BidResponse{Cur: "EUR"}, + SeatNonBid: []openrtb_ext.SeatNonBid{ + { + Seat: "appnexus", + NonBid: []openrtb_ext.NonBid{ + { + ImpId: "imp1", + StatusCode: int(nbr.LossBidLostInVastUnwrap), + Ext: openrtb_ext.ExtNonBid{ + Prebid: openrtb_ext.ExtNonBidPrebid{ + Bid: openrtb_ext.ExtNonBidPrebidBid{ + Price: 10, + ID: "bid-id-1", + W: 10, + H: 50, + OriginalBidCur: models.USD, + }, + }, + }, + }, + }, + }, + }, + }, + rCtx: &models.RequestCtx{ + CurrencyConversion: func(from, to string, value float64) (float64, error) { + if from == "USD" && to == "EUR" { + return value * 1.2, nil + } + if from == "EUR" && to == "USD" { + return value * 0.8, nil + } + return value, nil + }, + ImpBidCtx: map[string]models.ImpCtx{ + "imp1": { + Bidders: map[string]models.PartnerData{ + "appnexus": { + PartnerID: 1, + PrebidBidderCode: "appnexus", + KGP: "kgp", + KGPV: "kgpv", + }, + }, + BidCtx: map[string]models.BidCtx{ + "bid-id-1": { + BidExt: models.BidExt{ + ExtBid: openrtb_ext.ExtBid{}, + Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), + }, + }, + }, + BidFloor: 10.5, + BidFloorCur: "USD", + }, + }, + PartnerConfigMap: map[int]map[string]string{ + 1: { + "rev_share": "50", + }, + }, + WinningBids: make(models.WinningBids), + Platform: models.PLATFORM_APP, + }, + }, + partners: map[string][]PartnerRecord{ + "imp1": { + { + PartnerID: "appnexus", + BidderCode: "appnexus", + KGPV: "kgpv", + KGPSV: "kgpv", + PartnerSize: "10x50", + GrossECPM: 10, + NetECPM: 5, + BidID: "bid-id-1", + OrigBidID: "bid-id-1", + DealID: "-1", + ServerSide: 1, + OriginalCPM: 10, + OriginalCur: "USD", + FloorValue: 10.5, + FloorRuleValue: 10.5, + Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1461,6 +1762,7 @@ func TestGetPartnerRecordsByImpForSeatNonBidForFloors(t *testing.T) { FloorValue: 1, FloorCurrency: models.USD, }, + OriginalBidCPM: 10, }, }, }, @@ -1527,6 +1829,7 @@ func TestGetPartnerRecordsByImpForSeatNonBidForFloors(t *testing.T) { FloorValue: 0, FloorCurrency: models.USD, }, + OriginalBidCPM: 10, }, }, }, @@ -1593,6 +1896,7 @@ func TestGetPartnerRecordsByImpForSeatNonBidForFloors(t *testing.T) { FloorValue: 10, FloorCurrency: models.USD, }, + OriginalBidCPM: 10, }, }, }, @@ -1651,8 +1955,9 @@ func TestGetPartnerRecordsByImpForSeatNonBidForFloors(t *testing.T) { Ext: openrtb_ext.ExtNonBid{ Prebid: openrtb_ext.ExtNonBidPrebid{ Bid: openrtb_ext.ExtNonBidPrebidBid{ - Price: 10, - ID: "bid-id-1", + Price: 10, + ID: "bid-id-1", + OriginalBidCPM: 10, }, }, }, @@ -1711,8 +2016,9 @@ func TestGetPartnerRecordsByImpForSeatNonBidForFloors(t *testing.T) { Ext: openrtb_ext.ExtNonBid{ Prebid: openrtb_ext.ExtNonBidPrebid{ Bid: openrtb_ext.ExtNonBidPrebidBid{ - Price: 10, - ID: "bid-id-1", + Price: 10, + ID: "bid-id-1", + OriginalBidCPM: 10, }, }, }, @@ -1782,6 +2088,7 @@ func TestGetPartnerRecordsByImpForSeatNonBidForFloors(t *testing.T) { FloorValue: 1, FloorCurrency: "JPY", }, + OriginalBidCPM: 10, }, }, }, @@ -1988,6 +2295,7 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { BidId: "uuid", }, }, + OriginalBidCPM: 10, }, }, }, @@ -2017,6 +2325,11 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { name: "valid bid, but json unmarshal fails", args: args{ ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Cur: []string{}, + }, + }, Response: &openrtb2.BidResponse{ SeatBid: []openrtb2.SeatBid{ { @@ -2046,11 +2359,13 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { BidId: "uuid", }, }, + OriginalBidCPM: 10, }, }, }, }, }, + CurrencyConversion: func(from, to string, value float64) (float64, error) { return 10, nil }, }, }, partners: map[string][]PartnerRecord{ @@ -2066,6 +2381,7 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { OriginalCur: models.USD, NetECPM: 10, GrossECPM: 10, + OriginalCPM: 10, DealPriority: 0, }, }, @@ -2103,7 +2419,8 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { DealTierSatisfied: true, }, }, - Nbr: nbr.LossBidLostToHigherBid.Ptr(), + OriginalBidCPM: 10, + Nbr: nbr.LossBidLostToHigherBid.Ptr(), }, }, }, @@ -2195,9 +2512,10 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { Ext: openrtb_ext.ExtNonBid{ Prebid: openrtb_ext.ExtNonBidPrebid{ Bid: openrtb_ext.ExtNonBidPrebidBid{ - Price: 10, - ID: "bid-id-1", - BidId: "uuid", + Price: 10, + ID: "bid-id-1", + BidId: "uuid", + OriginalBidCPM: 10, }, }, }, @@ -2263,6 +2581,7 @@ func TestGetPartnerRecordsByImpForBidIDCollisions(t *testing.T) { BidId: "uuid", }, }, + OriginalBidCPM: 10, }, }, }, @@ -2318,6 +2637,9 @@ func TestGetPartnerRecordsByImpForBidExtFailure(t *testing.T) { name: "valid bid, but bid.ext is empty", args: args{ ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{}, + }, Response: &openrtb2.BidResponse{ SeatBid: []openrtb2.SeatBid{ { @@ -2352,6 +2674,7 @@ func TestGetPartnerRecordsByImpForBidExtFailure(t *testing.T) { }, }, }, + CurrencyConversion: func(from, to string, value float64) (float64, error) { return 10, nil }, }, }, partners: map[string][]PartnerRecord{ @@ -2367,6 +2690,7 @@ func TestGetPartnerRecordsByImpForBidExtFailure(t *testing.T) { OriginalCur: models.USD, NetECPM: 10, GrossECPM: 10, + OriginalCPM: 10, DealPriority: 0, }, }, @@ -2376,6 +2700,9 @@ func TestGetPartnerRecordsByImpForBidExtFailure(t *testing.T) { name: "dropped bid, bidExt unmarshal fails", args: args{ ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{}, + }, Response: &openrtb2.BidResponse{ SeatBid: []openrtb2.SeatBid{ { @@ -2410,6 +2737,7 @@ func TestGetPartnerRecordsByImpForBidExtFailure(t *testing.T) { }, }, }, + CurrencyConversion: func(from, to string, value float64) (float64, error) { return 10, nil }, }, }, partners: map[string][]PartnerRecord{ @@ -2425,6 +2753,7 @@ func TestGetPartnerRecordsByImpForBidExtFailure(t *testing.T) { OriginalCur: models.USD, NetECPM: 10, GrossECPM: 10, + OriginalCPM: 10, DealPriority: 0, Nbr: nil, }, @@ -3246,6 +3575,9 @@ func TestGetPartnerRecordsByImpForMarketPlaceBidders(t *testing.T) { name: "overwrite marketplace bid details", args: args{ ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{}, + }, Response: &openrtb2.BidResponse{ SeatBid: []openrtb2.SeatBid{ { @@ -3294,6 +3626,7 @@ func TestGetPartnerRecordsByImpForMarketPlaceBidders(t *testing.T) { }, }, }, + CurrencyConversion: func(from, to string, value float64) (float64, error) { return value, nil }, }, }, partners: map[string][]PartnerRecord{ @@ -3309,6 +3642,7 @@ func TestGetPartnerRecordsByImpForMarketPlaceBidders(t *testing.T) { OriginalCur: models.USD, GrossECPM: 1, NetECPM: 1, + OriginalCPM: 1, KGPV: "apnx_kgpv", KGPSV: "apnx_kgpv", }, @@ -3323,6 +3657,7 @@ func TestGetPartnerRecordsByImpForMarketPlaceBidders(t *testing.T) { OriginalCur: models.USD, GrossECPM: 2, NetECPM: 2, + OriginalCPM: 2, KGPV: "pubm_kgpv", KGPSV: "pubm_kgpv", }, @@ -3337,6 +3672,7 @@ func TestGetPartnerRecordsByImpForMarketPlaceBidders(t *testing.T) { OriginalCur: models.USD, GrossECPM: 3, NetECPM: 3, + OriginalCPM: 3, KGPV: "pubm_kgpv", KGPSV: "pubm_kgpv", }, @@ -4600,129 +4936,129 @@ func TestSlotRecordsInGetLogAuctionObjectAsURL(t *testing.T) { args args want want }{ - // { - // name: "req.Imp not mapped in ImpBidCtx", - // args: args{ - // ao: analytics.AuctionObject{ - // RequestWrapper: &openrtb_ext.RequestWrapper{ - // BidRequest: &openrtb2.BidRequest{ - // Imp: []openrtb2.Imp{ - // { - // ID: "imp1", - // TagID: "tagid", - // }, - // }, - // }, - // }, - // Response: &openrtb2.BidResponse{}, - // }, - // rCtx: &models.RequestCtx{ - // Endpoint: models.EndpointV25, - // PubID: 5890, - // }, - // logInfo: false, - // forRespExt: true, - // }, - // want: want{ - // logger: ow.cfg.Endpoint + `?json={"pubid":5890,"pid":"0","pdvid":"0","sl":1,"dvc":{},"ft":0,"it":"sdk"}&pubid=5890`, - // header: http.Header{ - // models.USER_AGENT_HEADER: []string{""}, - // models.IP_HEADER: []string{""}, - // }, - // }, - // }, - // { - // name: "multi imps request", - // args: args{ - // ao: analytics.AuctionObject{ - // RequestWrapper: &openrtb_ext.RequestWrapper{ - // BidRequest: &openrtb2.BidRequest{ - // Imp: []openrtb2.Imp{ - // { - // ID: "imp_1", - // TagID: "tagid_1", - // }, - // { - // ID: "imp_2", - // TagID: "tagid_2", - // }, - // }, - // }, - // }, - // Response: &openrtb2.BidResponse{}, - // }, - // rCtx: &models.RequestCtx{ - // PubID: 5890, - // Endpoint: models.EndpointV25, - // ImpBidCtx: map[string]models.ImpCtx{ - // "imp_1": { - // SlotName: "imp_1_tagid_1", - // AdUnitName: "tagid_1", - // }, - // "imp_2": { - // AdUnitName: "tagid_2", - // SlotName: "imp_2_tagid_2", - // }, - // }, - // }, - // logInfo: false, - // forRespExt: true, - // }, - // want: want{ - // logger: ow.cfg.Endpoint + `?json={"pubid":5890,"pid":"0","pdvid":"0","sl":1,"s":[{"sid":"sid","sn":"imp_1_tagid_1","au":"tagid_1","ps":[]},{"sid":"sid","sn":"imp_2_tagid_2","au":"tagid_2","ps":[]}],"dvc":{},"ft":0,"it":"sdk"}&pubid=5890`, - // header: http.Header{ - // models.USER_AGENT_HEADER: []string{""}, - // models.IP_HEADER: []string{""}, - // }, - // }, - // }, - // { - // name: "multi imps request and one request has incomingslots", - // args: args{ - // ao: analytics.AuctionObject{ - // RequestWrapper: &openrtb_ext.RequestWrapper{ - // BidRequest: &openrtb2.BidRequest{ - // Imp: []openrtb2.Imp{ - // { - // ID: "imp_1", - // TagID: "tagid_1", - // }, - // { - // ID: "imp_2", - // TagID: "tagid_2", - // }, - // }, - // }, - // }, - // Response: &openrtb2.BidResponse{}, - // }, - // rCtx: &models.RequestCtx{ - // PubID: 5890, - // Endpoint: models.EndpointV25, - // ImpBidCtx: map[string]models.ImpCtx{ - // "imp_1": { - // IncomingSlots: []string{"0x0v", "100x200"}, - // IsRewardInventory: ptrutil.ToPtr(int8(1)), - // SlotName: "imp_1_tagid_1", - // AdUnitName: "tagid_1", - // }, - // "imp_2": { - // AdUnitName: "tagid_2", - // SlotName: "imp_2_tagid_2", - // }, - // }, - // }, - // logInfo: false, - // forRespExt: true, - // }, - // want: want{ - // logger: ow.cfg.Endpoint + `?json={"pubid":5890,"pid":"0","pdvid":"0","sl":1,"s":[{"sid":"sid","sn":"imp_1_tagid_1","sz":["0x0v","100x200"],"au":"tagid_1","ps":[],"rwrd":1},{"sid":"sid","sn":"imp_2_tagid_2","au":"tagid_2","ps":[]}],"dvc":{},"ft":0,"it":"sdk"}&pubid=5890`, - // header: http.Header{ - // models.USER_AGENT_HEADER: []string{""}, - // models.IP_HEADER: []string{""}, - // }, - // }, - // }, + { + name: "req.Imp not mapped in ImpBidCtx", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + TagID: "tagid", + }, + }, + }, + }, + Response: &openrtb2.BidResponse{}, + }, + rCtx: &models.RequestCtx{ + Endpoint: models.EndpointV25, + PubID: 5890, + }, + logInfo: false, + forRespExt: true, + }, + want: want{ + logger: ow.cfg.Endpoint + `?json={"pubid":5890,"pid":"0","pdvid":"0","sl":1,"dvc":{},"ft":0,"it":"sdk"}&pubid=5890`, + header: http.Header{ + models.USER_AGENT_HEADER: []string{""}, + models.IP_HEADER: []string{""}, + }, + }, + }, + { + name: "multi imps request", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp_1", + TagID: "tagid_1", + }, + { + ID: "imp_2", + TagID: "tagid_2", + }, + }, + }, + }, + Response: &openrtb2.BidResponse{}, + }, + rCtx: &models.RequestCtx{ + PubID: 5890, + Endpoint: models.EndpointV25, + ImpBidCtx: map[string]models.ImpCtx{ + "imp_1": { + SlotName: "imp_1_tagid_1", + AdUnitName: "tagid_1", + }, + "imp_2": { + AdUnitName: "tagid_2", + SlotName: "imp_2_tagid_2", + }, + }, + }, + logInfo: false, + forRespExt: true, + }, + want: want{ + logger: ow.cfg.Endpoint + `?json={"pubid":5890,"pid":"0","pdvid":"0","sl":1,"s":[{"sid":"sid","sn":"imp_1_tagid_1","au":"tagid_1","ps":[]},{"sid":"sid","sn":"imp_2_tagid_2","au":"tagid_2","ps":[]}],"dvc":{},"ft":0,"it":"sdk"}&pubid=5890`, + header: http.Header{ + models.USER_AGENT_HEADER: []string{""}, + models.IP_HEADER: []string{""}, + }, + }, + }, + { + name: "multi imps request and one request has incomingslots", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp_1", + TagID: "tagid_1", + }, + { + ID: "imp_2", + TagID: "tagid_2", + }, + }, + }, + }, + Response: &openrtb2.BidResponse{}, + }, + rCtx: &models.RequestCtx{ + PubID: 5890, + Endpoint: models.EndpointV25, + ImpBidCtx: map[string]models.ImpCtx{ + "imp_1": { + IncomingSlots: []string{"0x0v", "100x200"}, + IsRewardInventory: ptrutil.ToPtr(int8(1)), + SlotName: "imp_1_tagid_1", + AdUnitName: "tagid_1", + }, + "imp_2": { + AdUnitName: "tagid_2", + SlotName: "imp_2_tagid_2", + }, + }, + }, + logInfo: false, + forRespExt: true, + }, + want: want{ + logger: ow.cfg.Endpoint + `?json={"pubid":5890,"pid":"0","pdvid":"0","sl":1,"s":[{"sid":"sid","sn":"imp_1_tagid_1","sz":["0x0v","100x200"],"au":"tagid_1","ps":[],"rwrd":1},{"sid":"sid","sn":"imp_2_tagid_2","au":"tagid_2","ps":[]}],"dvc":{},"ft":0,"it":"sdk"}&pubid=5890`, + header: http.Header{ + models.USER_AGENT_HEADER: []string{""}, + models.IP_HEADER: []string{""}, + }, + }, + }, { name: "multi imps request and one imp has partner record", args: args{ @@ -4943,3 +5279,97 @@ func Test_getFloorValueFromUpdatedRequest(t *testing.T) { }) } } + +func TestGetBidPriceAfterCurrencyConversion(t *testing.T) { + type args struct { + price float64 + requestCurrencies []string + responseCurrency string + currencyConverter func(fromCurrency string, toCurrency string, value float64) (float64, error) + } + tests := []struct { + name string + args args + want float64 + }{ + { + name: "Single request currency - successful conversion", + args: args{ + price: 100.0, + requestCurrencies: []string{"EUR"}, + responseCurrency: "USD", + currencyConverter: func(fromCurrency string, toCurrency string, value float64) (float64, error) { + if fromCurrency == "USD" && toCurrency == "EUR" { + return 85.0, nil // Assuming conversion rate USD to EUR is 0.85 + } + return 0, fmt.Errorf("unsupported conversion") + }, + }, + want: 85.0, + }, + { + name: "Multiple request currencies - first successful conversion", + args: args{ + price: 100.0, + requestCurrencies: []string{"EUR", "GBP"}, + responseCurrency: "USD", + currencyConverter: func(fromCurrency string, toCurrency string, value float64) (float64, error) { + if fromCurrency == "USD" && toCurrency == "EUR" { + return 85.0, nil // Successful conversion to EUR + } + return 0, fmt.Errorf("unsupported conversion") + }, + }, + want: 85.0, + }, + { + name: "Multiple request currencies - second successful conversion", + args: args{ + price: 100.0, + requestCurrencies: []string{"JPY", "GBP"}, + responseCurrency: "USD", + currencyConverter: func(fromCurrency string, toCurrency string, value float64) (float64, error) { + if fromCurrency == "USD" && toCurrency == "GBP" { + return 75.0, nil // Successful conversion to GBP + } + return 0, fmt.Errorf("unsupported conversion") + }, + }, + want: 75.0, + }, + { + name: "No request currencies provided - default to USD", + args: args{ + price: 100.0, + requestCurrencies: []string{}, + responseCurrency: "USD", + currencyConverter: func(fromCurrency string, toCurrency string, value float64) (float64, error) { + if fromCurrency == "USD" && toCurrency == "USD" { + return 100.0, nil // No conversion needed + } + return 0, fmt.Errorf("unsupported conversion") + }, + }, + want: 100.0, + }, + { + name: "Conversion fails for all currencies", + args: args{ + price: 100.0, + requestCurrencies: []string{"JPY", "CNY"}, + responseCurrency: "USD", + currencyConverter: func(fromCurrency string, toCurrency string, value float64) (float64, error) { + return 0, fmt.Errorf("conversion failed") + }, + }, + want: 0.0, // Default to 0 on failure + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GetBidPriceAfterCurrencyConversion(tt.args.price, tt.args.requestCurrencies, tt.args.responseCurrency, tt.args.currencyConverter) + assert.Equal(t, tt.want, got, "mismatched price") + }) + } +} diff --git a/go.mod b/go.mod index b9f7f938308..fed1b3bb174 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/PubMatic-OpenWrap/prebid-server/v2 go 1.20 -replace git.pubmatic.com/vastunwrap => git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240319050712-0b288cbb5a5d +replace git.pubmatic.com/vastunwrap => git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240827084017-0e392d3beb8b require ( github.com/DATA-DOG/go-sqlmock v1.5.0 @@ -90,7 +90,6 @@ require ( github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/sys v0.18.0 // indirect - github.com/yudai/pp v2.0.1+incompatible // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 13321359a53..c45d6edf1be 100644 --- a/go.sum +++ b/go.sum @@ -299,8 +299,8 @@ git.pubmatic.com/PubMatic/go-common v0.0.0-20240313090142-97ff3d63b7c3 h1:Ea8zwi git.pubmatic.com/PubMatic/go-common v0.0.0-20240313090142-97ff3d63b7c3/go.mod h1:c/I6IcDn4Mtq4mmw8wGJN3v0o10nIMX7VTuQnsalUw0= git.pubmatic.com/PubMatic/go-netacuity-client v0.0.0-20240104092757-5d6f15e25fe3 h1:zQUpPJOjTBGu2fIydrfRWphH7EWLlBE/Qgn64BSoccI= git.pubmatic.com/PubMatic/go-netacuity-client v0.0.0-20240104092757-5d6f15e25fe3/go.mod h1:w733mqJnHt0hLR9mIFMzyDR0D94qzc7mFHsuE0tFQho= -git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240319050712-0b288cbb5a5d h1:BgLUpJQ9Z89eDGz//voK74G/8FgjgVg2PWVbjgCJ4+A= -git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240319050712-0b288cbb5a5d/go.mod h1:kcoJf7k+xug8X8fLWmsiKhPnYP+k7RZkfUoUo5QF+KA= +git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240827084017-0e392d3beb8b h1:7AsXylZJDwq514L8KE0Id079VNfUsDEMUIYMlRYH+0Y= +git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240827084017-0e392d3beb8b/go.mod h1:kcoJf7k+xug8X8fLWmsiKhPnYP+k7RZkfUoUo5QF+KA= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= diff --git a/hooks/hookexecution/executor.go b/hooks/hookexecution/executor.go index 0ba466acc8d..2249fd29d42 100644 --- a/hooks/hookexecution/executor.go +++ b/hooks/hookexecution/executor.go @@ -260,10 +260,10 @@ func (e *hookExecutor) ExecuteRawBidderResponseStage(response *adapters.BidderRe stageName := hooks.StageRawBidderResponse.String() executionCtx := e.newContext(stageName) - payload := hookstage.RawBidderResponsePayload{Bids: response.Bids, Bidder: bidder} + payload := hookstage.RawBidderResponsePayload{BidderResponse: response, Bidder: bidder} outcome, payload, contexts, reject := executeStage(executionCtx, plan, payload, handler, e.metricEngine) - response.Bids = payload.Bids + response = payload.BidderResponse outcome.Entity = entity(bidder) outcome.Stage = stageName diff --git a/hooks/hookexecution/mocks_test.go b/hooks/hookexecution/mocks_test.go index a52fdbe12a7..968b1a7540b 100644 --- a/hooks/hookexecution/mocks_test.go +++ b/hooks/hookexecution/mocks_test.go @@ -154,7 +154,7 @@ func (e mockTimeoutHook) HandleRawBidderResponseHook(_ context.Context, _ hookst time.Sleep(20 * time.Millisecond) c := hookstage.ChangeSet[hookstage.RawBidderResponsePayload]{} c.AddMutation(func(payload hookstage.RawBidderResponsePayload) (hookstage.RawBidderResponsePayload, error) { - payload.Bids[0].BidMeta = &openrtb_ext.ExtBidPrebidMeta{AdapterCode: "new-code"} + payload.BidderResponse.Bids[0].BidMeta = &openrtb_ext.ExtBidPrebidMeta{AdapterCode: "new-code"} return payload, nil }, hookstage.MutationUpdate, "bidderResponse", "bidMeta.AdapterCode") @@ -371,7 +371,7 @@ func (e mockUpdateBidderResponseHook) HandleRawBidderResponseHook(_ context.Cont c := hookstage.ChangeSet[hookstage.RawBidderResponsePayload]{} c.AddMutation( func(payload hookstage.RawBidderResponsePayload) (hookstage.RawBidderResponsePayload, error) { - payload.Bids[0].DealPriority = 10 + payload.BidderResponse.Bids[0].DealPriority = 10 return payload, nil }, hookstage.MutationUpdate, "bidderResponse", "bid.deal-priority", ) diff --git a/hooks/hookstage/rawbidderresponse.go b/hooks/hookstage/rawbidderresponse.go index 7d08a7d2e02..1f6aaaa64ef 100644 --- a/hooks/hookstage/rawbidderresponse.go +++ b/hooks/hookstage/rawbidderresponse.go @@ -25,6 +25,6 @@ type RawBidderResponse interface { // objects representing bids returned by a particular bidder. // Hooks are allowed to modify bids using mutations. type RawBidderResponsePayload struct { - Bids []*adapters.TypedBid - Bidder string + BidderResponse *adapters.BidderResponse + Bidder string } diff --git a/hooks/hookstage/rawbidderresponse_mutations.go b/hooks/hookstage/rawbidderresponse_mutations.go index efab874fa15..c5022c31218 100644 --- a/hooks/hookstage/rawbidderresponse_mutations.go +++ b/hooks/hookstage/rawbidderresponse_mutations.go @@ -33,7 +33,7 @@ func (c ChangeSetBids[T]) Update(bids []*adapters.TypedBid) { c.changeSetRawBidderResponse.changeSet.AddMutation(func(p T) (T, error) { bidderPayload, err := c.changeSetRawBidderResponse.castPayload(p) if err == nil { - bidderPayload.Bids = bids + bidderPayload.BidderResponse.Bids = bids } if payload, ok := any(bidderPayload).(T); ok { return payload, nil diff --git a/modules/prebid/ortb2blocking/hook_raw_bidder_response.go b/modules/prebid/ortb2blocking/hook_raw_bidder_response.go index 215de260b09..e1a4d9c60dd 100644 --- a/modules/prebid/ortb2blocking/hook_raw_bidder_response.go +++ b/modules/prebid/ortb2blocking/hook_raw_bidder_response.go @@ -34,7 +34,7 @@ func handleRawBidderResponseHook( // allowedBids will store all bids that have passed the attribute check allowedBids := make([]*adapters.TypedBid, 0) - for _, bid := range payload.Bids { + for _, bid := range payload.BidderResponse.Bids { failedChecksData := make(map[string]interface{}) bidMediaTypes := mediaTypesFromBid(bid) @@ -77,7 +77,7 @@ func handleRawBidderResponseHook( } changeSet := hookstage.ChangeSet[hookstage.RawBidderResponsePayload]{} - if len(payload.Bids) != len(allowedBids) { + if len(payload.BidderResponse.Bids) != len(allowedBids) { changeSet.RawBidderResponse().Bids().Update(allowedBids) result.ChangeSet = changeSet } diff --git a/modules/prebid/ortb2blocking/module_test.go b/modules/prebid/ortb2blocking/module_test.go index 8178cba15fe..053fc9bfc75 100644 --- a/modules/prebid/ortb2blocking/module_test.go +++ b/modules/prebid/ortb2blocking/module_test.go @@ -614,9 +614,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }{ { description: "Payload not changed when empty account config and empty module contexts are provided. Analytic tags have successful records", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ADomain: []string{"foo"}, ImpID: impID1}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ADomain: []string{"foo"}, ImpID: impID1}, + }, }, }}, expectedBids: []*adapters.TypedBid{ @@ -643,9 +645,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Catch error if wrong data has been passed from previous hook. Payload not changed", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ADomain: []string{"foo"}, ImpID: impID1}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ADomain: []string{"foo"}, ImpID: impID1}, + }, }, }}, expectedBids: []*adapters.TypedBid{ @@ -658,12 +662,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by badv attribute check. Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": true}}}`), @@ -701,12 +707,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid not blocked because blocking conditions for current bidder do not exist. Payload not updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": true}}}`), @@ -742,12 +750,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid not blocked because enforce blocking is disabled by account config. Payload not updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": false}}}`), @@ -783,12 +793,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid not blocked because enforce blocking overridden for given bidder. Payload not updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": true, "action_overrides": {"enforce_blocks": [{"conditions": {"bidders": ["appnexus"]}, "override": false}]}}}}`), @@ -824,12 +836,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by badv attribute check (block unknown attributes). Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": true, "block_unknown_adomain": true}}}`), @@ -867,12 +881,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid not blocked because block unknown overridden for given bidder. Payload not updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": true, "block_unknown_adomain": true, "action_overrides": {"block_unknown_adomain": [{"conditions": {"bidders": ["appnexus"]}, "override": false}]}}}}`), @@ -908,12 +924,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid not blocked due to deal exception. Payload not updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1, DealID: "acceptDealID"}, - }, - { - Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, ImpID: impID1, DealID: "acceptDealID"}, + }, + { + Bid: &openrtb2.Bid{ID: "2", ADomain: []string{"good_domain"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"badv":{"enforce_blocks": true, "action_overrides": {"allowed_adomain_for_deals": [{"conditions": {"deal_ids": ["acceptDealID"]}, "override": ["forbidden_domain"]}]}}}}`), @@ -949,9 +967,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if there is an issue processing enforce blocks overrides for badv attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}}, + }, }, }}, config: json.RawMessage(`{"attributes": {"badv": {"enforce_blocks": true, "action_overrides": {"enforce_blocks": [{"conditions": {}}]}}}}`), @@ -974,9 +994,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if there is an issue processing block unknown domains overrides for badv attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}}, + }, }, }}, config: json.RawMessage(`{"attributes": {"badv": {"enforce_blocks": true, "action_overrides": {"block_unknown_adomain": [{"conditions": {}}]}}}}`), @@ -999,9 +1021,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if deal_ids not defined in config override conditions for badv attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, DealID: "acceptDealID"}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", ADomain: []string{"forbidden_domain"}, DealID: "acceptDealID"}, + }, }, }}, config: json.RawMessage(`{"attributes": {"badv": {"enforce_blocks": true, "action_overrides": {"allowed_adomain_for_deals": [{"conditions": {}}]}}}}`), @@ -1024,12 +1048,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by bcat attribute check. Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", Cat: []string{"moto"}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", Cat: []string{"moto"}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"bcat":{"enforce_blocks": true}}}`), @@ -1067,9 +1093,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if there is an issue processing enforce blocks overrides for bcat attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1}, + }, }, }}, config: json.RawMessage(`{"attributes": {"bcat": {"enforce_blocks": true, "action_overrides": {"enforce_blocks": [{"conditions": {}}]}}}}`), @@ -1092,9 +1120,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if there is an issue processing block unknown domains overrides for bcat attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1}, + }, }, }}, config: json.RawMessage(`{"attributes": {"bcat": {"enforce_blocks": true, "action_overrides": {"block_unknown_adv_cat": [{"conditions": {}}]}}}}`), @@ -1117,9 +1147,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if deal_ids not defined in config override conditions for bcat attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1, DealID: "acceptDealID"}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Cat: []string{"fishing"}, ImpID: impID1, DealID: "acceptDealID"}, + }, }, }}, config: json.RawMessage(`{"attributes": {"bcat": {"enforce_blocks": true, "action_overrides": {"allowed_adv_cat_for_deals": [{"conditions": {}}]}}}}`), @@ -1142,12 +1174,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by cattax attribute check. Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", CatTax: 1, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", CatTax: 2, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", CatTax: 1, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", CatTax: 2, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"bcat":{"enforce_blocks": true}}}`), @@ -1185,12 +1219,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by cattax attribute check (the default value used if no blocking attribute passed). Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", CatTax: 1, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", CatTax: 2, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", CatTax: 1, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", CatTax: 2, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"bcat":{"enforce_blocks": true}}}`), @@ -1227,12 +1263,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by bapp attribute check. Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Bundle: "forbidden_bundle", ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", Bundle: "allowed_bundle", ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Bundle: "forbidden_bundle", ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", Bundle: "allowed_bundle", ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"bapp":{"enforce_blocks": true}}}`), @@ -1270,9 +1308,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if there is an issue processing enforce blocks overrides for bapp attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Bundle: "forbidden_bundle", ImpID: impID1}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Bundle: "forbidden_bundle", ImpID: impID1}, + }, }, }}, config: json.RawMessage(`{"attributes": {"bapp": {"enforce_blocks": true, "action_overrides": {"enforce_blocks": [{"conditions": {}}]}}}}`), @@ -1295,9 +1335,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if deal_ids not defined in config override conditions for bapp attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Bundle: "forbidden_bundle", ImpID: impID1, DealID: "acceptDealID"}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Bundle: "forbidden_bundle", ImpID: impID1, DealID: "acceptDealID"}, + }, }, }}, config: json.RawMessage(`{"attributes": {"bapp": {"enforce_blocks": true, "action_overrides": {"allowed_app_for_deals": [{"conditions": {}}]}}}}`), @@ -1320,12 +1362,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by battr attribute check. Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Attr: []adcom1.CreativeAttribute{1}, ImpID: impID1}, - }, - { - Bid: &openrtb2.Bid{ID: "2", Attr: []adcom1.CreativeAttribute{2}, ImpID: impID2}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Attr: []adcom1.CreativeAttribute{1}, ImpID: impID1}, + }, + { + Bid: &openrtb2.Bid{ID: "2", Attr: []adcom1.CreativeAttribute{2}, ImpID: impID2}, + }, }, }}, config: json.RawMessage(`{"attributes":{"battr":{"enforce_blocks": true}}}`), @@ -1363,9 +1407,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if there is an issue processing enforce blocks overrides for battr attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Attr: []adcom1.CreativeAttribute{1}, ImpID: impID1}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Attr: []adcom1.CreativeAttribute{1}, ImpID: impID1}, + }, }, }}, config: json.RawMessage(`{"attributes": {"battr": {"enforce_blocks": true, "action_overrides": {"enforce_blocks": [{"conditions": {}}]}}}}`), @@ -1388,9 +1434,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Expect error if deal_ids not defined in config override conditions for battr attribute. Analytics should have error status tag", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ID: "1", Attr: []adcom1.CreativeAttribute{1}, ImpID: impID1, DealID: "acceptDealID"}, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ID: "1", Attr: []adcom1.CreativeAttribute{1}, ImpID: impID1, DealID: "acceptDealID"}, + }, }, }}, config: json.RawMessage(`{"attributes": {"battr": {"enforce_blocks": true, "action_overrides": {"allowed_banner_attr_for_deals": [{"conditions": {}}]}}}}`), @@ -1413,27 +1461,29 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { description: "Bid blocked by multiple attribute check. Payload updated. Analytic tags successfully collected", - payload: hookstage.RawBidderResponsePayload{Bidder: bidder, Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "1", - ADomain: []string{"forbidden_domain"}, - Cat: []string{"fishing"}, - CatTax: 1, - Bundle: "forbidden_bundle", - Attr: []adcom1.CreativeAttribute{1}, - ImpID: impID1, + payload: hookstage.RawBidderResponsePayload{Bidder: bidder, BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "1", + ADomain: []string{"forbidden_domain"}, + Cat: []string{"fishing"}, + CatTax: 1, + Bundle: "forbidden_bundle", + Attr: []adcom1.CreativeAttribute{1}, + ImpID: impID1, + }, }, - }, - { - Bid: &openrtb2.Bid{ - ID: "2", - ADomain: []string{"allowed_domain"}, - Cat: []string{"moto"}, - CatTax: 2, - Bundle: "allowed_bundle", - Attr: []adcom1.CreativeAttribute{2}, - ImpID: impID2, + { + Bid: &openrtb2.Bid{ + ID: "2", + ADomain: []string{"allowed_domain"}, + Cat: []string{"moto"}, + CatTax: 2, + Bundle: "allowed_bundle", + Attr: []adcom1.CreativeAttribute{2}, + ImpID: impID2, + }, }, }, }}, @@ -1514,7 +1564,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { assert.NoError(t, err) test.payload = newPayload } - assert.Equal(t, test.expectedBids, test.payload.Bids, "Invalid Bids returned after executing RawBidderResponse hook.") + assert.Equal(t, test.expectedBids, test.payload.BidderResponse.Bids, "Invalid Bids returned after executing RawBidderResponse hook.") // reset ChangeSet not to break hookResult assertion, we validated ChangeSet separately hookResult.ChangeSet = hookstage.ChangeSet[hookstage.RawBidderResponsePayload]{} diff --git a/modules/pubmatic/openwrap/config/config.go b/modules/pubmatic/openwrap/config/config.go index 0a634af2f62..112a50a2770 100755 --- a/modules/pubmatic/openwrap/config/config.go +++ b/modules/pubmatic/openwrap/config/config.go @@ -101,7 +101,6 @@ type PixelView struct { type FeatureToggle struct { VASTUnwrapPercent int - VASTUnwrapStatsPercent int AnalyticsThrottlingPercentage string } diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response.go b/modules/pubmatic/openwrap/hook_raw_bidder_response.go index 8bdc4f06b00..c7674f0c436 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response.go @@ -2,14 +2,20 @@ package openwrap import ( "fmt" - "sync" "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/nbr" + "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/prebid/prebid-server/v2/hooks/hookstage" ) +type BidUnwrapInfo struct { + bid *adapters.TypedBid + unwrapStatus string +} + func (m OpenWrap) handleRawBidderResponseHook( miCtx hookstage.ModuleInvocationContext, payload hookstage.RawBidderResponsePayload, @@ -20,41 +26,61 @@ func (m OpenWrap) handleRawBidderResponseHook( return result, nil } - if vastRequestContext.VastUnwrapEnabled { - // Do Unwrap and Update Adm - wg := new(sync.WaitGroup) - for _, bid := range payload.Bids { - if string(bid.BidType) == models.MediaTypeVideo { - wg.Add(1) - go func(bid *adapters.TypedBid) { - defer wg.Done() - m.unwrap.Unwrap(miCtx.AccountID, payload.Bidder, bid, vastRequestContext.UA, vastRequestContext.IP, vastRequestContext.VastUnwrapStatsEnabled) - }(bid) - } - } - wg.Wait() - changeSet := hookstage.ChangeSet[hookstage.RawBidderResponsePayload]{} - changeSet.RawBidderResponse().Bids().Update(payload.Bids) - result.ChangeSet = changeSet - } else { - vastRequestContext.VastUnwrapStatsEnabled = GetRandomNumberIn1To100() <= m.cfg.Features.VASTUnwrapStatsPercent - if vastRequestContext.VastUnwrapStatsEnabled { - // Do Unwrap and Collect stats only - for _, bid := range payload.Bids { - if string(bid.BidType) == models.MediaTypeVideo { - go func(bid *adapters.TypedBid) { - m.unwrap.Unwrap(miCtx.AccountID, payload.Bidder, bid, vastRequestContext.UA, vastRequestContext.IP, vastRequestContext.VastUnwrapStatsEnabled) - }(bid) - } - } + if !vastRequestContext.VastUnwrapEnabled { + return result, nil + } + + seatNonBid := openrtb_ext.NonBidCollection{} + unwrappedBids := make([]*adapters.TypedBid, 0, len(payload.BidderResponse.Bids)) + unwrappedBidsChan := make(chan BidUnwrapInfo, len(payload.BidderResponse.Bids)) + defer close(unwrappedBidsChan) + + unwrappedBidsCnt := 0 + // send bids for unwrap + for _, bid := range payload.BidderResponse.Bids { + if !isEligibleForUnwrap(bid) { + continue } + unwrappedBidsCnt++ + go func(bid adapters.TypedBid) { + unwrapStatus := m.unwrap.Unwrap(&bid, miCtx.AccountID, payload.Bidder, vastRequestContext.UA, vastRequestContext.IP) + unwrappedBidsChan <- BidUnwrapInfo{&bid, unwrapStatus} + }(*bid) } - if vastRequestContext.VastUnwrapEnabled || vastRequestContext.VastUnwrapStatsEnabled { - result.DebugMessages = append(result.DebugMessages, - fmt.Sprintf("For pubid:[%d] VastUnwrapEnabled: [%v] VastUnwrapStatsEnabled:[%v] ", - vastRequestContext.PubID, vastRequestContext.VastUnwrapEnabled, vastRequestContext.VastUnwrapStatsEnabled)) + // collect bids after unwrap + for i := 0; i < unwrappedBidsCnt; i++ { + unwrappedBid := <-unwrappedBidsChan + if !rejectBid(unwrappedBid.unwrapStatus) { + unwrappedBids = append(unwrappedBids, unwrappedBid.bid) + continue + } + seatNonBid.AddBid(openrtb_ext.NewNonBid(openrtb_ext.NonBidParams{ + Bid: unwrappedBid.bid.Bid, + NonBidReason: int(nbr.LossBidLostInVastUnwrap), + DealPriority: unwrappedBid.bid.DealPriority, + BidMeta: unwrappedBid.bid.BidMeta, + BidType: unwrappedBid.bid.BidType, + BidVideo: unwrappedBid.bid.BidVideo, + OriginalBidCur: payload.BidderResponse.Currency, + }), payload.Bidder, + ) } + changeSet := hookstage.ChangeSet[hookstage.RawBidderResponsePayload]{} + changeSet.RawBidderResponse().Bids().Update(unwrappedBids) + result.ChangeSet = changeSet + result.SeatNonBid = seatNonBid + result.DebugMessages = append(result.DebugMessages, + fmt.Sprintf("For pubid:[%d] VastUnwrapEnabled: [%v]", vastRequestContext.PubID, vastRequestContext.VastUnwrapEnabled)) + return result, nil } + +func isEligibleForUnwrap(bid *adapters.TypedBid) bool { + return bid != nil && bid.BidType == openrtb_ext.BidTypeVideo && bid.Bid != nil && bid.Bid.AdM != "" +} + +func rejectBid(bidUnwrapStatus string) bool { + return bidUnwrapStatus == models.UnwrapEmptyVASTStatus || bidUnwrapStatus == models.UnwrapInvalidVASTStatus +} diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go index 07130c3aed3..22bbf71b498 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go @@ -3,7 +3,6 @@ package openwrap import ( "fmt" "net/http" - "testing" unWrapCfg "git.pubmatic.com/vastunwrap/config" @@ -14,7 +13,9 @@ import ( "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/config" mock_metrics "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics/mock" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/nbr" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/unwrap" + "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) @@ -23,7 +24,6 @@ var invalidVastXMLAdM = "PubMaticAcudeo CompatibleVAST 2.0 Instream Test 1VAST 2.0 Instream Test 1https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&er=[ERRORCODE]https://track.dsptracker.com?p=1234&er=[ERRORCODE]https://aktrack.pubmatic.com/AdServer/AdDisplayTrackerServlet?operId=1&pubId=64195&siteId=47105&adId=1405154&adType=13&adServerId=243&kefact=1.000000&kaxefact=1.000000&kadNetFrequecy=0&kadwidth=0&kadheight=0&kadsizeid=97&kltstamp=1536933242&indirectAdId=0&adServerOptimizerId=2&ranreq=0.05969169352174375&kpbmtpfact=11.000000&dcId=1&tldId=0&passback=0&svr=ktk57&ekefact=er2bW2sDAwCra06ACbsIQySn5nqBtYsTl8fy5lupAexh37D_&ekaxefact=er2bW4EDAwB_LQpJJ23Fq0DcNC-NSAFXdpSQC8XBk_S33_Fa&ekpbmtpfact=er2bW5MDAwDJHdBnLBt5IrRuh7x0oqp_tjIALv_VvSQDAl6R&crID=m:1_x:3_y:3_p:11_va:3&lpu=ae.com&ucrid=678722001014421372&campaignId=16774&creativeId=0&pctr=0.000000&wDSPByrId=511&wDspId=27&wbId=0&wrId=0&wAdvID=3170&isRTB=1&rtbId=EBCA079F-8D7C-45B8-B733-92951F670AA1&imprId=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&oid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&pageURL=http%253A%252F%252Fowsdk-stagingams.pubmatic.com%253A8443%252Fvast-validator%252F%2523&sec=1&pmc=1https://DspImpressionTracker.com/https://mytracking.com/linear/closehttps://mytracking.com/linear/skiphttps://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=1https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=2https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=3https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=4https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=5https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=600:00:04https://www.automationtester.inhttps://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=99https://stagingams.pubmatic.com:8443/openwrap/media/pubmatic.mp4https://stagingams.pubmatic.com:8443/openwrap/media/pubmatic.mp4https://stagingams.pubmatic.com:8443/openwrap/media/mp4-sample-3.mp4" func TestHandleRawBidderResponseHook(t *testing.T) { - ctrl := gomock.NewController(t) defer ctrl.Finish() mockMetricsEngine := mock_metrics.NewMockMetricsEngine(ctrl) @@ -33,24 +33,21 @@ func TestHandleRawBidderResponseHook(t *testing.T) { payload hookstage.RawBidderResponsePayload moduleInvocationCtx hookstage.ModuleInvocationContext isAdmUpdated bool - randomNumber int } tests := []struct { - name string - args args - wantResult hookstage.HookResult[hookstage.RawBidderResponsePayload] - setup func() - wantErr bool - mockHandler http.HandlerFunc + name string + args args + wantResult hookstage.HookResult[hookstage.RawBidderResponsePayload] + setup func() + wantSeatNonBid openrtb_ext.NonBidCollection + mockHandler http.HandlerFunc }{ - { name: "Empty Request Context", args: args{ module: OpenWrap{}, }, wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{DebugMessages: []string{"error: request-ctx not found in handleRawBidderResponseHook()"}}, - wantErr: false, }, { name: "Set Vast Unwrapper to false in request context with type video", @@ -64,33 +61,30 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: "
This is an Ad
", - CrID: "Cr-234", - W: 100, - H: 50, - }, - BidType: "video", - }}}, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "
This is an Ad
", + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }}}}, moduleInvocationCtx: hookstage.ModuleInvocationContext{ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: false}}}, - randomNumber: 1, }, wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, - wantErr: false, }, { name: "Set Vast Unwrapper to false in request context with type video, stats enabled true", args: args{ module: OpenWrap{ cfg: config.Config{ - Features: config.FeatureToggle{ - VASTUnwrapStatsPercent: 2, - }, + Features: config.FeatureToggle{}, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, @@ -99,23 +93,23 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, - }, - BidType: "video", - }}, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }}}, Bidder: "pubmatic", }, moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: false}}}, - randomNumber: 1, }, mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Add("unwrap-status", "0") @@ -125,12 +119,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }), wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") - mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1") - mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) - mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()) }, - wantErr: false, }, { name: "Set Vast Unwrapper to true in request context with invalid vast xml", @@ -138,8 +127,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { module: OpenWrap{ cfg: config.Config{ Features: config.FeatureToggle{ - VASTUnwrapStatsPercent: 2, - VASTUnwrapPercent: 50, + VASTUnwrapPercent: 50, }, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, @@ -149,18 +137,20 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: invalidVastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: invalidVastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", }, - BidType: "video", }, }, Bidder: "pubmatic", @@ -176,9 +166,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "1") mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) }, - wantErr: true, }, - { name: "Set Vast Unwrapper to true in request context with type video", mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { @@ -191,8 +179,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { module: OpenWrap{ cfg: config.Config{ Features: config.FeatureToggle{ - VASTUnwrapStatsPercent: 2, - VASTUnwrapPercent: 50, + VASTUnwrapPercent: 50, }, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, @@ -202,34 +189,34 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", }, - BidType: "video", }, }, Bidder: "pubmatic", }, moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, - - isAdmUpdated: true, + isAdmUpdated: true, }, wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()).AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()).AnyTimes() + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") + mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1") + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) + mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()) }, - wantErr: false, }, { name: "Set Vast Unwrapper to true in request context for multiple bids with type video", @@ -237,8 +224,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { module: OpenWrap{ cfg: config.Config{ Features: config.FeatureToggle{ - VASTUnwrapStatsPercent: 2, - VASTUnwrapPercent: 50, + VASTUnwrapPercent: 50, }, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, @@ -248,36 +234,37 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, - }, - BidType: "video", - }, - { - Bid: &openrtb2.Bid{ - ID: "Bid-456", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-789", - W: 100, - H: 50, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", }, - BidType: "video", - }}, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "video", + }}, + }, Bidder: "pubmatic", }, moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, isAdmUpdated: true, - randomNumber: 10, }, mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Add("unwrap-status", "0") @@ -287,22 +274,19 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }), wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()).AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()).AnyTimes() + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0").Times(2) + mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1").Times(2) + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()).Times(2) + mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()).Times(2) }, - wantErr: false, }, - { name: "Set Vast Unwrapper to true in request context for multiple bids with different type", args: args{ module: OpenWrap{ cfg: config.Config{ Features: config.FeatureToggle{ - VASTUnwrapStatsPercent: 2, - VASTUnwrapPercent: 50, + VASTUnwrapPercent: 50, }, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, @@ -312,36 +296,37 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", }, - BidType: "video", - }, - { - Bid: &openrtb2.Bid{ - ID: "Bid-456", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: "This is banner creative", - CrID: "Cr-789", - W: 100, - H: 50, - }, - BidType: "banner", - }}, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }}, + }, Bidder: "pubmatic", }, moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, - - isAdmUpdated: true, + isAdmUpdated: true, }, mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Add("unwrap-status", "0") @@ -351,12 +336,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }), wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "0").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()).AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "0", gomock.Any()).AnyTimes() + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") + mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "0") + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) + mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "0", gomock.Any()) }, - wantErr: false, }, { name: "Set Vast Unwrapper to true in request context with type video and source owsdk", @@ -364,8 +348,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { module: OpenWrap{ cfg: config.Config{ Features: config.FeatureToggle{ - VASTUnwrapStatsPercent: 2, - VASTUnwrapPercent: 50, + VASTUnwrapPercent: 50, }, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, @@ -375,25 +358,26 @@ func TestHandleRawBidderResponseHook(t *testing.T) { metricEngine: mockMetricsEngine, }, payload: hookstage.RawBidderResponsePayload{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", }, - BidType: "video", }, }, Bidder: "pubmatic", }, moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, - - isAdmUpdated: true, + isAdmUpdated: true, }, mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Add("unwrap-status", "0") @@ -403,12 +387,141 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }), wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1").AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()).AnyTimes() - mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()).AnyTimes() + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") + mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1") + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) + mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()) + }, + }, + { + name: "bid with InvalidVAST should be discarded and should be present in seatNonBid", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{ + VASTUnwrapPercent: 50, + }, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: invalidVastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, + }, + mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Add("unwrap-status", models.UnwrapInvalidVASTStatus) + w.WriteHeader(http.StatusNoContent) + }), + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + setup: func() { + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", models.UnwrapInvalidVASTStatus) + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) + }, + wantSeatNonBid: func() openrtb_ext.NonBidCollection { + seatNonBid := openrtb_ext.NonBidCollection{} + seatNonBid.AddBid(openrtb_ext.NonBid{ + ImpId: fmt.Sprintf("div-adunit-%d", 123), + StatusCode: int(nbr.LossBidLostInVastUnwrap), + Ext: openrtb_ext.ExtNonBid{ + Prebid: openrtb_ext.ExtNonBidPrebid{ + Bid: openrtb_ext.ExtNonBidPrebidBid{ + Price: 2.1, + ID: "Bid-123", + W: 100, + H: 50, + Type: openrtb_ext.BidTypeVideo, + }, + }, + }, + }, "pubmatic") + return seatNonBid + }(), + }, + { + name: "bid with EmptyVAST should be discarded and should be present in seatNonBid", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{ + VASTUnwrapPercent: 50, + }, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: invalidVastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, + }, + mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Add("unwrap-status", models.UnwrapEmptyVASTStatus) + w.WriteHeader(http.StatusNoContent) + }), + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + setup: func() { + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", models.UnwrapEmptyVASTStatus) + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) }, - wantErr: false, + wantSeatNonBid: func() openrtb_ext.NonBidCollection { + seatNonBid := openrtb_ext.NonBidCollection{} + seatNonBid.AddBid(openrtb_ext.NonBid{ + ImpId: fmt.Sprintf("div-adunit-%d", 123), + StatusCode: int(nbr.LossBidLostInVastUnwrap), + Ext: openrtb_ext.ExtNonBid{ + Prebid: openrtb_ext.ExtNonBidPrebid{ + Bid: openrtb_ext.ExtNonBidPrebidBid{ + Price: 2.1, + ID: "Bid-123", + W: 100, + H: 50, + Type: openrtb_ext.BidTypeVideo, + }, + }, + }, + }, "pubmatic") + return seatNonBid + }(), }, } for _, tt := range tests { @@ -417,19 +530,56 @@ func TestHandleRawBidderResponseHook(t *testing.T) { tt.setup() } - GetRandomNumberIn1To100 = func() int { - return tt.args.randomNumber - } - m := tt.args.module m.unwrap = unwrap.NewUnwrap("http://localhost:8001/unwrap", 200, tt.mockHandler, m.metricEngine) - _, err := m.handleRawBidderResponseHook(tt.args.moduleInvocationCtx, tt.args.payload) - if !assert.NoError(t, err, tt.wantErr) { - return - } + hookResult, _ := m.handleRawBidderResponseHook(tt.args.moduleInvocationCtx, tt.args.payload) if tt.args.moduleInvocationCtx.ModuleContext != nil && tt.args.isAdmUpdated { - assert.Equal(t, inlineXMLAdM, tt.args.payload.Bids[0].Bid.AdM, "AdM is not updated correctly after executing RawBidderResponse hook.") + assert.Equal(t, inlineXMLAdM, tt.args.payload.BidderResponse.Bids[0].Bid.AdM, "AdM is not updated correctly after executing RawBidderResponse hook.") } + assert.Equal(t, tt.wantSeatNonBid, hookResult.SeatNonBid, "mismatched seatNonBids") + }) + } +} + +func TestIsEligibleForUnwrap(t *testing.T) { + type args struct { + bid *adapters.TypedBid + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Bid is nil", + args: args{bid: nil}, + want: false, + }, + { + name: "Bid.Bid is nil", + args: args{bid: &adapters.TypedBid{Bid: nil}}, + want: false, + }, + { + name: "AdM is empty", + args: args{bid: &adapters.TypedBid{Bid: &openrtb2.Bid{AdM: ""}}}, + want: false, + }, + { + name: "BidType is not video", + args: args{bid: &adapters.TypedBid{Bid: &openrtb2.Bid{AdM: "some_adm"}, BidType: openrtb_ext.BidTypeBanner}}, + want: false, + }, + { + name: "Bid is eligible for unwrap", + args: args{bid: &adapters.TypedBid{Bid: &openrtb2.Bid{AdM: "some_adm"}, BidType: openrtb_ext.BidTypeVideo}}, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := isEligibleForUnwrap(tt.args.bid) + assert.Equal(t, tt.want, got) }) } } diff --git a/modules/pubmatic/openwrap/models/constants.go b/modules/pubmatic/openwrap/models/constants.go index 94f124cbb27..ac4d50e686a 100755 --- a/modules/pubmatic/openwrap/models/constants.go +++ b/modules/pubmatic/openwrap/models/constants.go @@ -371,21 +371,23 @@ const ( Enabled = "1" // VAST Unwrap - RequestContext = "rctx" - UnwrapCount = "unwrap-count" - UnwrapStatus = "unwrap-status" - Timeout = "Timeout" - UnwrapSucessStatus = "0" - UnwrapTimeout = "unwrap-timeout" - MediaTypeVideo = "video" - ProfileId = "profileID" - VersionId = "versionID" - DisplayId = "DisplayID" - XUserIP = "X-Forwarded-For" - XUserAgent = "X-Device-User-Agent" - CreativeID = "unwrap-ucrid" - PubID = "pub_id" - ImpressionID = "imr_id" + RequestContext = "rctx" + UnwrapCount = "unwrap-count" + UnwrapStatus = "unwrap-status" + Timeout = "Timeout" + UnwrapSucessStatus = "0" + UnwrapEmptyVASTStatus = "4" + UnwrapInvalidVASTStatus = "6" + UnwrapTimeout = "unwrap-timeout" + MediaTypeVideo = "video" + ProfileId = "profileID" + VersionId = "versionID" + DisplayId = "DisplayID" + XUserIP = "X-Forwarded-For" + XUserAgent = "X-Device-User-Agent" + CreativeID = "unwrap-ucrid" + PubID = "pub_id" + ImpressionID = "imr_id" //Constants for new SDK reporting ProfileTypeKey = "type" diff --git a/modules/pubmatic/openwrap/models/nbr/codes.go b/modules/pubmatic/openwrap/models/nbr/codes.go index 7eafb8a5d09..fa54481d8d1 100644 --- a/modules/pubmatic/openwrap/models/nbr/codes.go +++ b/modules/pubmatic/openwrap/models/nbr/codes.go @@ -9,6 +9,7 @@ const ( RequestBlockedSlotNotMapped openrtb3.NoBidReason = 503 RequestBlockedPartnerThrottle openrtb3.NoBidReason = 504 RequestBlockedPartnerFiltered openrtb3.NoBidReason = 505 + LossBidLostInVastUnwrap openrtb3.NoBidReason = 506 ) // Openwrap module specific codes diff --git a/modules/pubmatic/openwrap/unwrap/unwrap.go b/modules/pubmatic/openwrap/unwrap/unwrap.go index ef002929116..24c5b24ba38 100644 --- a/modules/pubmatic/openwrap/unwrap/unwrap.go +++ b/modules/pubmatic/openwrap/unwrap/unwrap.go @@ -40,21 +40,17 @@ func NewUnwrap(Endpoint string, DefaultTime int, handler http.HandlerFunc, Metri } -func (uw Unwrap) Unwrap(accountID, bidder string, bid *adapters.TypedBid, userAgent, ip string, isStatsEnabled bool) { +func (uw Unwrap) Unwrap(bid *adapters.TypedBid, accountID, bidder, userAgent, ip string) (unwrapStatus string) { startTime := time.Now() var wrapperCnt int64 - var respStatus string - if bid == nil || bid.Bid == nil || bid.Bid.AdM == "" { - return - } defer func() { if r := recover(); r != nil { glog.Errorf("AdM:[%s] Error:[%v] stacktrace:[%s]", bid.Bid.AdM, r, string(debug.Stack())) } respTime := time.Since(startTime) uw.metricEngine.RecordUnwrapRequestTime(accountID, bidder, respTime) - uw.metricEngine.RecordUnwrapRequestStatus(accountID, bidder, respStatus) - if respStatus == "0" { + uw.metricEngine.RecordUnwrapRequestStatus(accountID, bidder, unwrapStatus) + if unwrapStatus == "0" { uw.metricEngine.RecordUnwrapWrapperCount(accountID, bidder, strconv.Itoa(int(wrapperCnt))) uw.metricEngine.RecordUnwrapRespTime(accountID, strconv.Itoa(int(wrapperCnt)), respTime) } @@ -76,13 +72,14 @@ func (uw Unwrap) Unwrap(accountID, bidder string, bid *adapters.TypedBid, userAg httpReq.Header = headers httpResp := NewCustomRecorder() uw.unwrapRequest(httpResp, httpReq) - respStatus = httpResp.Header().Get(models.UnwrapStatus) + unwrapStatus = httpResp.Header().Get(models.UnwrapStatus) wrapperCnt, _ = strconv.ParseInt(httpResp.Header().Get(models.UnwrapCount), 10, 0) - if !isStatsEnabled && httpResp.Code == http.StatusOK && respStatus == models.UnwrapSucessStatus { + if httpResp.Code == http.StatusOK && unwrapStatus == models.UnwrapSucessStatus { respBody := httpResp.Body.Bytes() bid.Bid.AdM = string(respBody) } - glog.V(models.LogLevelDebug).Infof("[VAST_UNWRAPPER] pubid:[%v] bidder:[%v] impid:[%v] bidid:[%v] status_code:[%v] wrapper_cnt:[%v] httpRespCode= [%v] statsEnabled:[%v]", - accountID, bidder, bid.Bid.ImpID, bid.Bid.ID, respStatus, wrapperCnt, httpResp.Code, isStatsEnabled) + glog.V(models.LogLevelDebug).Infof("[VAST_UNWRAPPER] pubid:[%v] bidder:[%v] impid:[%v] bidid:[%v] status_code:[%v] wrapper_cnt:[%v] httpRespCode= [%v]", + accountID, bidder, bid.Bid.ImpID, bid.Bid.ID, unwrapStatus, wrapperCnt, httpResp.Code) + return unwrapStatus } diff --git a/modules/pubmatic/openwrap/unwrap/unwrap_test.go b/modules/pubmatic/openwrap/unwrap/unwrap_test.go index a7f3e7be050..763ba071c8c 100644 --- a/modules/pubmatic/openwrap/unwrap/unwrap_test.go +++ b/modules/pubmatic/openwrap/unwrap/unwrap_test.go @@ -8,7 +8,6 @@ import ( "github.com/golang/mock/gomock" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" - metrics "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics" mock_metrics "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics/mock" "github.com/stretchr/testify/assert" ) @@ -18,35 +17,32 @@ var invalidVastXMLAdM = "PubMaticAcudeo CompatibleVAST 2.0 Instream Test 1VAST 2.0 Instream Test 1https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&er=[ERRORCODE]https://track.dsptracker.com?p=1234&er=[ERRORCODE]https://aktrack.pubmatic.com/AdServer/AdDisplayTrackerServlet?operId=1&pubId=64195&siteId=47105&adId=1405154&adType=13&adServerId=243&kefact=1.000000&kaxefact=1.000000&kadNetFrequecy=0&kadwidth=0&kadheight=0&kadsizeid=97&kltstamp=1536933242&indirectAdId=0&adServerOptimizerId=2&ranreq=0.05969169352174375&kpbmtpfact=11.000000&dcId=1&tldId=0&passback=0&svr=ktk57&ekefact=er2bW2sDAwCra06ACbsIQySn5nqBtYsTl8fy5lupAexh37D_&ekaxefact=er2bW4EDAwB_LQpJJ23Fq0DcNC-NSAFXdpSQC8XBk_S33_Fa&ekpbmtpfact=er2bW5MDAwDJHdBnLBt5IrRuh7x0oqp_tjIALv_VvSQDAl6R&crID=m:1_x:3_y:3_p:11_va:3&lpu=ae.com&ucrid=678722001014421372&campaignId=16774&creativeId=0&pctr=0.000000&wDSPByrId=511&wDspId=27&wbId=0&wrId=0&wAdvID=3170&isRTB=1&rtbId=EBCA079F-8D7C-45B8-B733-92951F670AA1&imprId=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&oid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&pageURL=http%253A%252F%252Fowsdk-stagingams.pubmatic.com%253A8443%252Fvast-validator%252F%2523&sec=1&pmc=1https://DspImpressionTracker.com/https://mytracking.com/linear/closehttps://mytracking.com/linear/skiphttps://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=1https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=2https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=3https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=4https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=5https://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=600:00:04https://www.automationtester.inhttps://aktrack.pubmatic.com/track?operId=7&p=64195&s=47105&a=1405154&wa=243&ts=1536933242&wc=16774&crId=m:1_x:3_y:3_p:11_va:3&ucrid=678722001014421372&impid=24D9FEDA-C97D-4DF7-B747-BD3CFF5AC7B5&advertiser_id=3170&ecpm=1.000000&e=99https://stagingams.pubmatic.com:8443/openwrap/media/pubmatic.mp4https://stagingams.pubmatic.com:8443/openwrap/media/pubmatic.mp4https://stagingams.pubmatic.com:8443/openwrap/media/mp4-sample-3.mp4" func TestUnwrap_Unwrap(t *testing.T) { - ctrl := gomock.NewController(t) defer ctrl.Finish() mockMetricsEngine := mock_metrics.NewMockMetricsEngine(ctrl) type fields struct { - endpoint string - defaultTime int - metricEngine metrics.MetricsEngine - unwrapRequest http.HandlerFunc + endpoint string } type args struct { - accountID string - bidder string - bid *adapters.TypedBid - userAgent string - ip string - isStatsEnabled bool + accountID string + bidder string + bid *adapters.TypedBid + userAgent string + ip string } tests := []struct { - name string - fields fields - args args - setup func() - mockHandler http.HandlerFunc - expectedAdm string + name string + fields fields + args args + setup func() + mockHandler http.HandlerFunc + expectedAdm string + expectedUnwrapStatus string }{ { - name: "Stats enabled only", + name: "Unwrap enabled with valid adm", + fields: fields{endpoint: "http://localhost:8001/unwrap"}, args: args{ accountID: "5890", bidder: "pubmatic", @@ -55,9 +51,8 @@ func TestUnwrap_Unwrap(t *testing.T) { AdM: vastXMLAdM, }, }, - userAgent: "UA", - ip: "10.12.13.14", - isStatsEnabled: true, + userAgent: "UA", + ip: "10.12.13.14", }, setup: func() { mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") @@ -69,40 +64,39 @@ func TestUnwrap_Unwrap(t *testing.T) { w.Header().Add("unwrap-status", "0") w.Header().Add("unwrap-count", "1") w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(vastXMLAdM)) + _, _ = w.Write([]byte(inlineXMLAdM)) }), - expectedAdm: vastXMLAdM, + expectedAdm: inlineXMLAdM, + expectedUnwrapStatus: "0", }, { - name: "Unwrap enabled with valid adm", + name: "Unwrap enabled with invalid adm", + fields: fields{endpoint: "http://localhost:8001/unwrap"}, args: args{ accountID: "5890", bidder: "pubmatic", bid: &adapters.TypedBid{ Bid: &openrtb2.Bid{ - AdM: vastXMLAdM, + AdM: invalidVastXMLAdM, }, }, - userAgent: "UA", - ip: "10.12.13.14", - isStatsEnabled: false, + userAgent: "UA", + ip: "10.12.13.14", }, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") - mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "1") + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "1") mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) - mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()) }, mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Add("unwrap-status", "0") - w.Header().Add("unwrap-count", "1") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(inlineXMLAdM)) + w.Header().Add("unwrap-status", "1") + w.WriteHeader(http.StatusNoContent) }), - expectedAdm: inlineXMLAdM, + expectedAdm: invalidVastXMLAdM, + expectedUnwrapStatus: "1", }, { - name: "Unwrap enabled with invalid adm", + name: "Error while forming the HTTPRequest for unwrap process", + fields: fields{endpoint: ":"}, args: args{ accountID: "5890", bidder: "pubmatic", @@ -111,33 +105,29 @@ func TestUnwrap_Unwrap(t *testing.T) { AdM: invalidVastXMLAdM, }, }, - userAgent: "UA", - ip: "10.12.13.14", - isStatsEnabled: false, + userAgent: "UA", + ip: "10.12.13.14", }, setup: func() { - mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "1") + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "") mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) }, - mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Add("unwrap-status", "1") - w.WriteHeader(http.StatusNoContent) - }), - expectedAdm: invalidVastXMLAdM, + mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {}), + expectedAdm: invalidVastXMLAdM, + expectedUnwrapStatus: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if tt.setup != nil { tt.setup() } - uw := NewUnwrap("http://localhost:8001/unwrap", 200, tt.mockHandler, mockMetricsEngine) - uw.Unwrap(tt.args.accountID, tt.args.bidder, tt.args.bid, tt.args.userAgent, tt.args.ip, tt.args.isStatsEnabled) - if !tt.args.isStatsEnabled && strings.Compare(tt.args.bid.Bid.AdM, tt.expectedAdm) != 0 { + uw := NewUnwrap(tt.fields.endpoint, 200, tt.mockHandler, mockMetricsEngine) + unwrapStatus := uw.Unwrap(tt.args.bid, tt.args.accountID, tt.args.bidder, tt.args.userAgent, tt.args.ip) + if strings.Compare(tt.args.bid.Bid.AdM, tt.expectedAdm) != 0 { assert.Equal(t, inlineXMLAdM, tt.args.bid.Bid.AdM, "AdM is not updated correctly after unwrap ") - } + assert.Equal(t, tt.expectedUnwrapStatus, unwrapStatus, "mismatched unwrap status") }) } } From cce5d99f144c81ba78b2b57868bc03da72ad3deb Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:32:24 +0530 Subject: [PATCH 04/24] OTT-1863 :: Support to read adpod configs from UI in openwrap module (#889) --- modules/pubmatic/openwrap/adpod/adpod.go | 196 ++++++++++-- .../openwrap/adpod/auction/auction.go | 13 +- .../adpod/impressions/duration_ranges.go | 13 +- .../openwrap/adpod/impressions/impression.go | 23 +- .../pubmatic/openwrap/beforevalidationhook.go | 48 ++- .../openwrap/beforevalidationhook_test.go | 288 +++++++++++++++++- .../cache/gocache/adpod_config_test.go | 12 +- .../database/mysql/adpod_config_test.go | 14 +- modules/pubmatic/openwrap/entrypointhook.go | 5 +- modules/pubmatic/openwrap/models/adpod.go | 9 + .../models/adpodconfig/adpodconfig.go | 26 +- modules/pubmatic/openwrap/models/openwrap.go | 30 +- modules/pubmatic/openwrap/models/request.go | 19 +- modules/pubmatic/openwrap/ortb/imp.go | 115 +++++++ .../pubmatic/openwrap/processedauctionhook.go | 2 +- 15 files changed, 720 insertions(+), 93 deletions(-) create mode 100644 modules/pubmatic/openwrap/ortb/imp.go diff --git a/modules/pubmatic/openwrap/adpod/adpod.go b/modules/pubmatic/openwrap/adpod/adpod.go index 91e1ff290eb..f6f6cdeec6d 100644 --- a/modules/pubmatic/openwrap/adpod/adpod.go +++ b/modules/pubmatic/openwrap/adpod/adpod.go @@ -3,13 +3,16 @@ package adpod import ( "encoding/json" "errors" + "fmt" "github.com/buger/jsonparser" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/cache" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adpodconfig" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" - "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/utils" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/ortb" "github.com/prebid/prebid-server/v2/util/ptrutil" ) @@ -32,30 +35,19 @@ func setDefaultValues(adpodConfig *models.AdPod) { } -func GetAdpodConfigs(impVideo *openrtb2.Video, requestExtConfigs *models.ExtRequestAdPod, adUnitConfig *adunitconfig.AdConfig, partnerConfigMap map[int]map[string]string, pubId string, me metrics.MetricsEngine) (*models.AdPod, error) { - adpodConfigs, ok, err := resolveAdpodConfigs(impVideo, requestExtConfigs, adUnitConfig, pubId, me) +func GetV25AdpodConfigs(impVideo *openrtb2.Video, requestExtConfigs *models.ExtRequestAdPod, adUnitConfig *adunitconfig.AdConfig, partnerConfigMap map[int]map[string]string, pubId string, me metrics.MetricsEngine) (*models.AdPod, error) { + adpodConfigs, ok, err := resolveV25AdpodConfigs(impVideo, requestExtConfigs, adUnitConfig, pubId, me) if !ok || err != nil { return nil, err } - videoAdDuration := models.GetVersionLevelPropertyFromPartnerConfig(partnerConfigMap, models.VideoAdDurationKey) - if len(videoAdDuration) > 0 { - adpodConfigs.VideoAdDuration = utils.GetIntArrayFromString(videoAdDuration, models.ArraySeparator) - } - - videoAdDurationMatchingPolicy := models.GetVersionLevelPropertyFromPartnerConfig(partnerConfigMap, models.VideoAdDurationMatchingKey) - if len(videoAdDurationMatchingPolicy) > 0 { - adpodConfigs.VideoAdDurationMatching = videoAdDurationMatchingPolicy - } - // Set default value if adpod object does not exists setDefaultValues(adpodConfigs) return adpodConfigs, nil - } -func resolveAdpodConfigs(impVideo *openrtb2.Video, requestExtConfigs *models.ExtRequestAdPod, adUnitConfig *adunitconfig.AdConfig, pubId string, me metrics.MetricsEngine) (*models.AdPod, bool, error) { +func resolveV25AdpodConfigs(impVideo *openrtb2.Video, requestExtConfigs *models.ExtRequestAdPod, adUnitConfig *adunitconfig.AdConfig, pubId string, me metrics.MetricsEngine) (*models.AdPod, bool, error) { var adpodConfig *models.AdPod // Check in impression extension @@ -79,10 +71,9 @@ func resolveAdpodConfigs(impVideo *openrtb2.Video, requestExtConfigs *models.Ext } return nil, false, nil - } -func Validate(config *models.AdPod) error { +func ValidateV25Configs(rCtx models.RequestCtx, config *models.AdPod) error { if config == nil { return nil } @@ -119,9 +110,9 @@ func Validate(config *models.AdPod) error { return errors.New("adpod.adminduration must be less than adpod.admaxduration") } - if len(config.VideoAdDuration) > 0 { + if rCtx.AdpodProfileConfig != nil && len(rCtx.AdpodProfileConfig.AdserverCreativeDurations) > 0 { validDurations := false - for _, videoDuration := range config.VideoAdDuration { + for _, videoDuration := range rCtx.AdpodProfileConfig.AdserverCreativeDurations { if videoDuration >= config.MinDuration && videoDuration <= config.MaxDuration { validDurations = true break @@ -135,3 +126,170 @@ func Validate(config *models.AdPod) error { return nil } + +func GetAdpodConfigs(rctx models.RequestCtx, cache cache.Cache, adunit *adunitconfig.AdConfig) ([]models.PodConfig, error) { + // Fetch Adpod Configs from UI + pods, err := cache.GetAdpodConfig(rctx.PubID, rctx.ProfileID, rctx.DisplayVersionID) + if err != nil { + return nil, err + } + + var uiAdpodConfigs []models.PodConfig + if pods != nil { + uiAdpodConfigs = append(uiAdpodConfigs, decouplePodConfigs(pods)...) + } + + // Vmap adpod configs + var adrules []models.PodConfig + if adunit != nil && adunit.Adrule != nil { + for _, rule := range adunit.Adrule { + if rule != nil { + adrules = append(adrules, models.PodConfig{ + PodID: rule.PodID, + PodDur: rule.PodDur, + MaxSeq: rule.MaxSeq, + MinDuration: rule.MinDuration, + MaxDuration: rule.MaxDuration, + RqdDurs: rule.RqdDurs, + }) + } + } + } + + var podConfigs []models.PodConfig + if len(uiAdpodConfigs) > 0 && adunit.Video != nil && adunit.Video.UsePodConfig != nil && *adunit.Video.UsePodConfig { + podConfigs = append(podConfigs, uiAdpodConfigs...) + } else if len(adrules) > 0 && rctx.AdruleFlag { + podConfigs = append(podConfigs, adrules...) + } + + return podConfigs, nil +} + +func decouplePodConfigs(pods *adpodconfig.AdpodConfig) []models.PodConfig { + if pods == nil { + return nil + } + + var podConfigs []models.PodConfig + // Add all dynamic adpods + for i, dynamic := range pods.Dynamic { + podConfigs = append(podConfigs, models.PodConfig{ + PodID: fmt.Sprintf("dynamic-%d", i+1), + PodDur: dynamic.PodDur, + MaxSeq: dynamic.MaxSeq, + MinDuration: dynamic.MinDuration, + MaxDuration: dynamic.MaxDuration, + RqdDurs: dynamic.RqdDurs, + }) + } + + // Add all structured adpods + for i, structured := range pods.Structured { + podConfigs = append(podConfigs, models.PodConfig{ + PodID: fmt.Sprintf("structured-%d", i+1), + MinDuration: structured.MinDuration, + MaxDuration: structured.MaxDuration, + RqdDurs: structured.RqdDurs, + }) + } + + // Add all hybrid adpods + for i, hybrid := range pods.Hybrid { + pod := models.PodConfig{ + PodID: fmt.Sprintf("hybrid-%d", i+1), + MinDuration: hybrid.MinDuration, + MaxDuration: hybrid.MaxDuration, + RqdDurs: hybrid.RqdDurs, + } + + if hybrid.PodDur != nil { + pod.PodDur = *hybrid.PodDur + } + + if hybrid.MaxSeq != nil { + pod.MaxSeq = *hybrid.MaxSeq + } + + podConfigs = append(podConfigs, pod) + } + + return podConfigs +} + +func ValidateAdpodConfigs(configs []models.PodConfig) error { + for _, config := range configs { + if config.RqdDurs == nil && config.MinDuration == 0 && config.MaxDuration == 0 { + return errors.New("slot duration is missing in adpod config") + } + + if config.MinDuration > config.MaxDuration { + return errors.New("min duration should be less than max duration") + } + + if config.RqdDurs == nil && config.MaxDuration <= 0 { + return errors.New("max duration should be greater than 0") + } + + if config.PodDur < 0 { + return errors.New("pod duration should be positive number") + } + + if config.MaxSeq < 0 { + return errors.New("max sequence should be positive number") + } + } + + return nil +} + +func ApplyAdpodConfigs(rctx models.RequestCtx, bidRequest *openrtb2.BidRequest) *openrtb2.BidRequest { + if len(rctx.ImpAdPodConfig) == 0 { + return bidRequest + } + + imps := make([]openrtb2.Imp, 0) + for _, imp := range bidRequest.Imp { + if imp.Video == nil { + imps = append(imps, imp) + continue + } + + // Give priority to adpod config in request + if len(imp.Video.PodID) > 0 { + imps = append(imps, imp) + continue + } + + impPodConfig, ok := rctx.ImpAdPodConfig[imp.ID] + if !ok || len(impPodConfig) == 0 { + imps = append(imps, imp) + continue + } + + // Apply adpod config + for i, podConfig := range impPodConfig { + impCopy := ortb.DeepCloneImpression(&imp) + impCopy.ID = fmt.Sprintf("%s-%s-%d", impCopy.ID, podConfig.PodID, i) + impCopy.Video.PodID = podConfig.PodID + impCopy.Video.MaxSeq = podConfig.MaxSeq + impCopy.Video.PodDur = podConfig.PodDur + impCopy.Video.MinDuration = podConfig.MinDuration + impCopy.Video.MaxDuration = podConfig.MaxDuration + impCopy.Video.RqdDurs = podConfig.RqdDurs + + impCtx := rctx.ImpBidCtx[imp.ID] + impCtxCopy := impCtx.DeepCopy() + impCtxCopy.Video = impCopy.Video + + rctx.ImpBidCtx[impCopy.ID] = impCtxCopy + imps = append(imps, *impCopy) + } + + // Delete original imp from context + delete(rctx.ImpBidCtx, imp.ID) + } + + bidRequest.Imp = imps + return bidRequest +} diff --git a/modules/pubmatic/openwrap/adpod/auction/auction.go b/modules/pubmatic/openwrap/adpod/auction/auction.go index 4ededc7e7fc..be0b81d5d15 100644 --- a/modules/pubmatic/openwrap/adpod/auction/auction.go +++ b/modules/pubmatic/openwrap/adpod/auction/auction.go @@ -39,7 +39,7 @@ func FormAdpodBidsAndPerformExclusion(response *openrtb2.BidResponse, rctx model return nil, errs } - impAdpodBidsMap, _ := generateAdpodBids(response.SeatBid, rctx.ImpBidCtx) + impAdpodBidsMap, _ := generateAdpodBids(response.SeatBid, rctx.ImpBidCtx, rctx.AdpodProfileConfig) adpodBids, errs := doAdPodExclusions(impAdpodBidsMap, rctx.ImpBidCtx) if len(errs) > 0 { return nil, errs @@ -77,7 +77,7 @@ func addTargetingKey(bid *openrtb2.Bid, key openrtb_ext.TargetingKey, value stri return err } -func generateAdpodBids(seatBids []openrtb2.SeatBid, impCtx map[string]models.ImpCtx) (map[string]*AdPodBid, []openrtb2.SeatBid) { +func generateAdpodBids(seatBids []openrtb2.SeatBid, impCtx map[string]models.ImpCtx, adpodProfileCfg *models.AdpodProfileConfig) (map[string]*AdPodBid, []openrtb2.SeatBid) { impAdpodBidsMap := make(map[string]*AdPodBid) videoSeatBids := make([]openrtb2.SeatBid, 0) @@ -133,12 +133,13 @@ func generateAdpodBids(seatBids []openrtb2.SeatBid, impCtx map[string]models.Imp // } //get duration of creative - duration, status := getBidDuration(bid, *eachImpCtx.AdpodConfig, eachImpCtx.ImpAdPodCfg, sequence) + duration, status := getBidDuration(bid, *eachImpCtx.AdpodConfig, adpodProfileCfg, eachImpCtx.ImpAdPodCfg, sequence) if eachImpCtx.BidIDToDur == nil { eachImpCtx.BidIDToDur = map[string]int64{} } eachImpCtx.BidIDToDur[bid.ID] = duration impCtx[impId] = eachImpCtx + eachImpBid := Bid{ Bid: bid, ExtBid: ext, @@ -185,7 +186,7 @@ it will try to get the actual ad duration returned by the bidder using prebid.vi if prebid.video.duration not present then uses defaultDuration passed as an argument if video lengths matching policy is present for request then it will validate and update duration based on policy */ -func getBidDuration(bid *openrtb2.Bid, adpodConfig models.AdPod, config []*models.ImpAdPodConfig, sequence int) (int64, int64) { +func getBidDuration(bid *openrtb2.Bid, adpodConfig models.AdPod, adpodProfileCfg *models.AdpodProfileConfig, config []*models.ImpAdPodConfig, sequence int) (int64, int64) { // C1: Read it from bid.ext.prebid.video.duration field duration, err := jsonparser.GetInt(bid.Ext, "prebid", "video", "duration") @@ -201,8 +202,8 @@ func getBidDuration(bid *openrtb2.Bid, adpodConfig models.AdPod, config []*model } // C2: Based on video lengths matching policy validate and return duration - if len(adpodConfig.VideoAdDurationMatching) > 0 { - return getDurationBasedOnDurationMatchingPolicy(duration, adpodConfig.VideoAdDurationMatching, config) + if adpodProfileCfg != nil && len(adpodProfileCfg.AdserverCreativeDurationMatchingPolicy) > 0 { + return getDurationBasedOnDurationMatchingPolicy(duration, adpodProfileCfg.AdserverCreativeDurationMatchingPolicy, config) } //default return duration which is present in bid.ext.prebid.vide.duration field diff --git a/modules/pubmatic/openwrap/adpod/impressions/duration_ranges.go b/modules/pubmatic/openwrap/adpod/impressions/duration_ranges.go index d086cb2d83e..1ff280064f5 100644 --- a/modules/pubmatic/openwrap/adpod/impressions/duration_ranges.go +++ b/modules/pubmatic/openwrap/adpod/impressions/duration_ranges.go @@ -12,14 +12,19 @@ type DurRangeConfig struct { //IImpressions interface } // newByDurationRanges will create new object ob byDurRangeConfig for creating impressions for adpod request -func newByDurationRanges(policy string, durations []int, maxAds, adMinDuration, adMaxDuration int) DurRangeConfig { - return DurRangeConfig{ - policy: policy, - durations: durations, +func newByDurationRanges(adpodProfileCfg *models.AdpodProfileConfig, maxAds, adMinDuration, adMaxDuration int) DurRangeConfig { + cfg := DurRangeConfig{ maxAds: maxAds, adMinDuration: adMinDuration, adMaxDuration: adMaxDuration, } + + if adpodProfileCfg != nil { + cfg.durations = adpodProfileCfg.AdserverCreativeDurations + cfg.policy = adpodProfileCfg.AdserverCreativeDurationMatchingPolicy + } + + return cfg } // Get function returns lists of min,max duration ranges ganerated based on durations diff --git a/modules/pubmatic/openwrap/adpod/impressions/impression.go b/modules/pubmatic/openwrap/adpod/impressions/impression.go index 4535b49a845..f1fd6e7be4c 100644 --- a/modules/pubmatic/openwrap/adpod/impressions/impression.go +++ b/modules/pubmatic/openwrap/adpod/impressions/impression.go @@ -27,14 +27,14 @@ type ImpGenerator interface { // Algorithm() int // returns algorithm used for computing number of impressions } -func GenerateImpressions(request *openrtb_ext.RequestWrapper, impCtx map[string]models.ImpCtx, pubId string, me metrics.MetricsEngine) ([]*openrtb_ext.ImpWrapper, []error) { +func GenerateImpressions(request *openrtb_ext.RequestWrapper, impCtx map[string]models.ImpCtx, adpodProfileCfg *models.AdpodProfileConfig, pubId string, me metrics.MetricsEngine) ([]*openrtb_ext.ImpWrapper, []error) { var imps []*openrtb_ext.ImpWrapper var errs []error for _, impWrapper := range request.GetImp() { eachImpCtx := impCtx[impWrapper.ID] - impAdpodConfig, err := getAdPodImpConfig(impWrapper.Imp, eachImpCtx.AdpodConfig) + impAdpodConfig, err := getAdPodImpConfig(impWrapper.Imp, eachImpCtx.AdpodConfig, adpodProfileCfg) if impAdpodConfig == nil { imps = append(imps, impWrapper) if err != nil { @@ -95,13 +95,13 @@ func generateImpressionID(impID string, seqNo int) string { } // getAdPodImpsConfigs will return number of impressions configurations within adpod -func getAdPodImpConfig(imp *openrtb2.Imp, adpod *models.AdPod) ([]*models.ImpAdPodConfig, error) { +func getAdPodImpConfig(imp *openrtb2.Imp, adpod *models.AdPod, adpodProfileCfg *models.AdpodProfileConfig) ([]*models.ImpAdPodConfig, error) { // This case for non adpod video impression if adpod == nil { return nil, nil } - selectedAlgorithm := SelectAlgorithm(adpod) - impGen := NewImpressions(imp.Video.MinDuration, imp.Video.MaxDuration, adpod, selectedAlgorithm) + selectedAlgorithm := SelectAlgorithm(adpod, adpodProfileCfg) + impGen := NewImpressions(imp.Video.MinDuration, imp.Video.MaxDuration, adpod, adpodProfileCfg, selectedAlgorithm) impRanges := impGen.Get() // labels := metrics.PodLabels{AlgorithmName: impressions.MonitorKey[selectedAlgorithm], NoOfImpressions: new(int)} @@ -132,10 +132,10 @@ func getAdPodImpConfig(imp *openrtb2.Imp, adpod *models.AdPod) ([]*models.ImpAdP // Return Value: // - MinMaxAlgorithm (default) // - ByDurationRanges: if reqAdPod extension has VideoAdDuration and VideoAdDurationMatchingPolicy is "exact" algorithm -func SelectAlgorithm(reqAdPod *models.AdPod) int { +func SelectAlgorithm(reqAdPod *models.AdPod, adpodProfileCfg *models.AdpodProfileConfig) int { if reqAdPod != nil { - if len(reqAdPod.VideoAdDuration) > 0 && - (models.OWExactVideoAdDurationMatching == reqAdPod.VideoAdDurationMatching || models.OWRoundupVideoAdDurationMatching == reqAdPod.VideoAdDurationMatching) { + if adpodProfileCfg != nil && len(adpodProfileCfg.AdserverCreativeDurations) > 0 && + (models.OWExactVideoAdDurationMatching == adpodProfileCfg.AdserverCreativeDurationMatchingPolicy || models.OWRoundupVideoAdDurationMatching == adpodProfileCfg.AdserverCreativeDurationMatchingPolicy) { return models.ByDurationRanges } } @@ -146,7 +146,7 @@ func SelectAlgorithm(reqAdPod *models.AdPod) int { // based on input algorithm type // if invalid algorithm type is passed, it returns default algorithm which will compute // impressions based on minimum ad slot duration -func NewImpressions(podMinDuration, podMaxDuration int64, adpod *models.AdPod, algorithm int) ImpGenerator { +func NewImpressions(podMinDuration, podMaxDuration int64, adpod *models.AdPod, adpodProfileCfg *models.AdpodProfileConfig, algorithm int) ImpGenerator { switch algorithm { case models.MaximizeForDuration: g := newMaximizeForDuration(podMinDuration, podMaxDuration, adpod) @@ -157,10 +157,7 @@ func NewImpressions(podMinDuration, podMaxDuration int64, adpod *models.AdPod, a return &g case models.ByDurationRanges: - g := newByDurationRanges(adpod.VideoAdDurationMatching, adpod.VideoAdDuration, - int(adpod.MaxAds), - adpod.MinDuration, adpod.MaxDuration) - + g := newByDurationRanges(adpodProfileCfg, int(adpod.MaxAds), adpod.MinDuration, adpod.MaxDuration) return &g } diff --git a/modules/pubmatic/openwrap/beforevalidationhook.go b/modules/pubmatic/openwrap/beforevalidationhook.go index 058b8b4b5bd..c6cd5c25246 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook.go +++ b/modules/pubmatic/openwrap/beforevalidationhook.go @@ -27,6 +27,7 @@ import ( "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" modelsAdunitConfig "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/nbr" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/utils" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/prebid/prebid-server/v2/util/ptrutil" ) @@ -170,6 +171,15 @@ func (m OpenWrap) handleBeforeValidationHook( } } + videoAdDuration := models.GetVersionLevelPropertyFromPartnerConfig(partnerConfigMap, models.VideoAdDurationKey) + policy := models.GetVersionLevelPropertyFromPartnerConfig(partnerConfigMap, models.VideoAdDurationMatchingKey) + if len(videoAdDuration) > 0 { + rCtx.AdpodProfileConfig = &models.AdpodProfileConfig{ + AdserverCreativeDurations: utils.GetIntArrayFromString(videoAdDuration, models.ArraySeparator), + AdserverCreativeDurationMatchingPolicy: policy, + } + } + rCtx.PartnerConfigMap = partnerConfigMap // keep a copy at module level as well if ver, err := strconv.Atoi(models.GetVersionLevelPropertyFromPartnerConfig(partnerConfigMap, models.DisplayVersionID)); err == nil { rCtx.DisplayVersionID = ver @@ -386,7 +396,7 @@ func (m OpenWrap) handleBeforeValidationHook( var adpodConfig *models.AdPod if rCtx.IsCTVRequest { - adpodConfig, err = adpod.GetAdpodConfigs(imp.Video, requestExt.AdPod, videoAdUnitCtx.AppliedSlotAdUnitConfig, partnerConfigMap, rCtx.PubIDStr, m.metricEngine) + adpodConfig, err = adpod.GetV25AdpodConfigs(imp.Video, requestExt.AdPod, videoAdUnitCtx.AppliedSlotAdUnitConfig, partnerConfigMap, rCtx.PubIDStr, m.metricEngine) if err != nil { result.NbrCode = int(nbr.InvalidAdpodConfig) result.Errors = append(result.Errors, "failed to get adpod configurations for "+imp.ID+" reason: "+err.Error()) @@ -395,19 +405,39 @@ func (m OpenWrap) handleBeforeValidationHook( } //Adding default durations for CTV Test requests - if rCtx.IsTestRequest > 0 && adpodConfig != nil && adpodConfig.VideoAdDuration == nil { - adpodConfig.VideoAdDuration = []int{5, 10} + if rCtx.IsTestRequest > 0 && adpodConfig != nil && rCtx.AdpodProfileConfig == nil { + rCtx.AdpodProfileConfig = &models.AdpodProfileConfig{ + AdserverCreativeDurations: []int{5, 10}, + AdserverCreativeDurationMatchingPolicy: openrtb_ext.OWRoundupVideoAdDurationMatching, + } } - if rCtx.IsTestRequest > 0 && adpodConfig != nil && len(adpodConfig.VideoAdDurationMatching) == 0 { - adpodConfig.VideoAdDurationMatching = openrtb_ext.OWRoundupVideoAdDurationMatching + + if err := adpod.ValidateV25Configs(rCtx, adpodConfig); err != nil { + result.NbrCode = int(nbr.InvalidAdpodConfig) + result.Errors = append(result.Errors, "invalid adpod configurations for "+imp.ID+" reason: "+err.Error()) + rCtx.ImpBidCtx = getDefaultImpBidCtx(*payload.BidRequest) + return result, nil } - if err := adpod.Validate(adpodConfig); err != nil { + podConfigs, err := adpod.GetAdpodConfigs(rCtx, m.cache, videoAdUnitCtx.AppliedSlotAdUnitConfig) + if err != nil { + result.NbrCode = int(nbr.InvalidAdpodConfig) + result.Errors = append(result.Errors, "failed to get adpod configurations for "+imp.ID+" reason: "+err.Error()) + rCtx.ImpBidCtx = getDefaultImpBidCtx(*payload.BidRequest) + return result, nil + } + + err = adpod.ValidateAdpodConfigs(podConfigs) + if err != nil { result.NbrCode = int(nbr.InvalidAdpodConfig) result.Errors = append(result.Errors, "invalid adpod configurations for "+imp.ID+" reason: "+err.Error()) rCtx.ImpBidCtx = getDefaultImpBidCtx(*payload.BidRequest) return result, nil } + + if len(podConfigs) > 0 { + rCtx.ImpAdPodConfig[imp.ID] = podConfigs + } } bidderMeta := make(map[string]models.PartnerData) @@ -632,6 +662,10 @@ func (m OpenWrap) handleBeforeValidationHook( result.ChangeSet.AddMutation(func(ep hookstage.BeforeValidationRequestPayload) (hookstage.BeforeValidationRequestPayload, error) { rctx := moduleCtx.ModuleContext["rctx"].(models.RequestCtx) + defer func() { + moduleCtx.ModuleContext["rctx"] = rctx + }() + var err error if rctx.IsCTVRequest && ep.BidRequest.Source != nil && ep.BidRequest.Source.SChain != nil { err = ctv.IsValidSchain(ep.BidRequest.Source.SChain) @@ -651,6 +685,8 @@ func (m OpenWrap) handleBeforeValidationHook( if err != nil { result.Errors = append(result.Errors, err.Error()) } + + ep.BidRequest = adpod.ApplyAdpodConfigs(rctx, ep.BidRequest) } return ep, err }, hookstage.MutationUpdate, "request-body-with-profile-data") diff --git a/modules/pubmatic/openwrap/beforevalidationhook_test.go b/modules/pubmatic/openwrap/beforevalidationhook_test.go index a31dcc803ed..13d8cf44fe5 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook_test.go +++ b/modules/pubmatic/openwrap/beforevalidationhook_test.go @@ -23,8 +23,8 @@ import ( metrics "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics" mock_metrics "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics/mock" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adpodconfig" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" - modelsAdunitConfig "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/nbr" mock_profilemetadata "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/profilemetadata/mock" mock_feature "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/publisherfeature/mock" @@ -4291,6 +4291,278 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { nilCurrencyConversion: false, }, }, + { + name: "Read_adpod_configs_from_UI_and_update_request_impressions_with_configs", + args: args{ + ctx: context.Background(), + moduleCtx: hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + "rctx": models.RequestCtx{ + PubID: 5890, + PubIDStr: "5890", + ProfileID: 4444, + ProfileIDStr: "4444", + DisplayID: 1, + SSAuction: 1, + Platform: "video", + Debug: true, + UA: "go-test", + IP: "127.0.0.1", + IsCTVRequest: true, + UidCookie: &http.Cookie{ + Name: "uids", + Value: `eyJ0ZW1wVUlEcyI6eyIzM2Fjcm9zcyI6eyJ1aWQiOiIxMTkxNzkxMDk5Nzc2NjEiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OTo0My4zODg4Nzk5NVoifSwiYWRmIjp7InVpZCI6IjgwNDQ2MDgzMzM3Nzg4MzkwNzgiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMS4wMzMwNTQ3MjdaIn0sImFka2VybmVsIjp7InVpZCI6IkE5MTYzNTAwNzE0OTkyOTMyOTkwIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MDkuMzczMzg1NjYyWiJ9LCJhZGtlcm5lbEFkbiI6eyJ1aWQiOiJBOTE2MzUwMDcxNDk5MjkzMjk5MCIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEzLjQzNDkyNTg5NloifSwiYWRtaXhlciI6eyJ1aWQiOiIzNjZhMTdiMTJmMjI0ZDMwOGYzZTNiOGRhOGMzYzhhMCIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA5LjU5MjkxNDgwMVoifSwiYWRueHMiOnsidWlkIjoiNDE5Mjg5ODUzMDE0NTExOTMiLCJleHBpcmVzIjoiMjAyMy0wMS0xOFQwOTo1MzowOC44MjU0NDI2NzZaIn0sImFqYSI6eyJ1aWQiOiJzMnN1aWQ2RGVmMFl0bjJveGQ1aG9zS1AxVmV3IiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTMuMjM5MTc2MDU0WiJ9LCJlcGxhbm5pbmciOnsidWlkIjoiQUoxRjBTOE5qdTdTQ0xWOSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEwLjkyOTk2MDQ3M1oifSwiZ2Ftb3NoaSI6eyJ1aWQiOiJndXNyXzM1NmFmOWIxZDhjNjQyYjQ4MmNiYWQyYjdhMjg4MTYxIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTAuNTI0MTU3MjI1WiJ9LCJncmlkIjp7InVpZCI6IjRmYzM2MjUwLWQ4NTItNDU5Yy04NzcyLTczNTZkZTE3YWI5NyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjE0LjY5NjMxNjIyN1oifSwiZ3JvdXBtIjp7InVpZCI6IjdENzVEMjVGLUZBQzktNDQzRC1CMkQxLUIxN0ZFRTExRTAyNyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjM5LjIyNjIxMjUzMloifSwiaXgiOnsidWlkIjoiWW9ORlNENlc5QkphOEh6eEdtcXlCUUFBXHUwMDI2Mjk3IiwiZXhwaXJlcyI6IjIwMjMtMDUtMzFUMDc6NTM6MzguNTU1ODI3MzU0WiJ9LCJqaXhpZSI6eyJ1aWQiOiI3MzY3MTI1MC1lODgyLTExZWMtYjUzOC0xM2FjYjdhZjBkZTQiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMi4xOTEwOTk3MzJaIn0sImxvZ2ljYWQiOnsidWlkIjoiQVZ4OVROQS11c25pa3M4QURzTHpWa3JvaDg4QUFBR0JUREh0UUEiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OTowOS40NTUxNDk2MTZaIn0sIm1lZGlhbmV0Ijp7InVpZCI6IjI5Nzg0MjM0OTI4OTU0MTAwMDBWMTAiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMy42NzIyMTUxMjhaIn0sIm1naWQiOnsidWlkIjoibTU5Z1hyN0xlX1htIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTcuMDk3MDAxNDcxWiJ9LCJuYW5vaW50ZXJhY3RpdmUiOnsidWlkIjoiNmFlYzhjMTAzNzlkY2I3ODQxMmJjODBiNmRkOWM5NzMxNzNhYjdkNzEyZTQzMWE1YTVlYTcwMzRlNTZhNThhMCIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjE2LjcxNDgwNzUwNVoifSwib25ldGFnIjp7InVpZCI6IjdPelZoVzFOeC1LOGFVak1HMG52NXVNYm5YNEFHUXZQbnVHcHFrZ3k0ckEiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OTowOS4xNDE3NDEyNjJaIn0sIm9wZW54Ijp7InVpZCI6IjVkZWNlNjIyLTBhMjMtMGRhYi0zYTI0LTVhNzcwMTBlNDU4MiIsImV4cGlyZXMiOiIyMDIzLTA1LTMxVDA3OjUyOjQ3LjE0MDQxNzM2M1oifSwicHVibWF0aWMiOnsidWlkIjoiN0Q3NUQyNUYtRkFDOS00NDNELUIyRDEtQjE3RkVFMTFFMDI3IiwiZXhwaXJlcyI6IjIwMjItMTAtMzFUMDk6MTQ6MjUuNzM3MjU2ODk5WiJ9LCJyaWNoYXVkaWVuY2UiOnsidWlkIjoiY2I2YzYzMjAtMzNlMi00Nzc0LWIxNjAtMXp6MTY1NDg0MDc0OSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA5LjUyNTA3NDE4WiJ9LCJzbWFydHlhZHMiOnsidWlkIjoiMTJhZjE1ZTQ0ZjAwZDA3NjMwZTc0YzQ5MTU0Y2JmYmE0Zjg0N2U4ZDRhMTU0YzhjM2Q1MWY1OGNmNzJhNDYyNyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEwLjgyNTAzMTg4NFoifSwic21pbGV3YW50ZWQiOnsidWlkIjoiZGQ5YzNmZTE4N2VmOWIwOWNhYTViNzExNDA0YzI4MzAiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxNC4yNTU2MDkzNjNaIn0sInN5bmFjb3JtZWRpYSI6eyJ1aWQiOiJHRFBSIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MDkuOTc5NTgzNDM4WiJ9LCJ0cmlwbGVsaWZ0Ijp7InVpZCI6IjcwMjE5NzUwNTQ4MDg4NjUxOTQ2MyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA4Ljk4OTY3MzU3NFoifSwidmFsdWVpbXByZXNzaW9uIjp7InVpZCI6IjlkMDgxNTVmLWQ5ZmUtNGI1OC04OThlLWUyYzU2MjgyYWIzZSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA5LjA2NzgzOTE2NFoifSwidmlzeCI6eyJ1aWQiOiIyN2UwYWMzYy1iNDZlLTQxYjMtOTkyYy1mOGQyNzE0OTQ5NWUiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMi45ODk1MjM1NzNaIn0sInlpZWxkbGFiIjp7InVpZCI6IjY5NzE0ZDlmLWZiMDAtNGE1Zi04MTljLTRiZTE5MTM2YTMyNSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjExLjMwMzAyNjYxNVoifSwieWllbGRtbyI6eyJ1aWQiOiJnOTZjMmY3MTlmMTU1MWIzMWY2MyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEwLjExMDUyODYwOVoifSwieWllbGRvbmUiOnsidWlkIjoiMmE0MmZiZDMtMmM3MC00ZWI5LWIxYmQtMDQ2OTY2NTBkOTQ4IiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTAuMzE4MzMzOTM5WiJ9LCJ6ZXJvY2xpY2tmcmF1ZCI6eyJ1aWQiOiJiOTk5NThmZS0yYTg3LTJkYTQtOWNjNC05NjFmZDExM2JlY2UiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxNS43MTk1OTQ1NjZaIn19LCJiZGF5IjoiMjAyMi0wNS0xN1QwNjo0ODozOC4wMTc5ODgyMDZaIn0=`, + }, + KADUSERCookie: &http.Cookie{ + Name: "KADUSERCOOKIE", + Value: `7D75D25F-FAC9-443D-B2D1-B17FEE11E027`, + }, + OriginCookie: "go-test", + Endpoint: models.EndpointJson, + Method: "POST", + Aliases: make(map[string]string), + ImpBidCtx: make(map[string]models.ImpCtx), + PrebidBidderCode: make(map[string]string), + BidderResponseTimeMillis: make(map[string]int), + SeatNonBids: make(map[string][]openrtb_ext.NonBid), + MetricsEngine: mockEngine, + AdruleFlag: false, + AdpodProfileConfig: nil, + ImpAdPodConfig: make(map[string][]models.PodConfig), + }, + }, + }, + bidrequest: json.RawMessage(`{"id":"1559039248176","test":0,"at":1,"tmax":500,"source":{"fd":1,"tid":"1559039248176","pchain":"pchaintagid"},"imp":[{"id":"28635736ddc2bb2","ext":{"bidder":{"appnexus":{"keywords":[],"dealtier":{"prefix":"apnx","mindealtier":4}}}},"displaymanager":"PubMaticSDK","displaymanagerver":"PubMaticSDK-1.0","instl":1,"tagid":"adunit","bidfloor":1,"bidfloorcur":"USD","secure":0,"iframebuster":["1"],"exp":1,"video":{"mimes":["video/3gpp","video/mp4"],"minduration":10,"maxduration":40,"protocols":[2,3,5,6],"w":280,"h":360,"startdelay":1,"placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3],"playbackend":1}}],"site":{"id":"123","name":"EbayShopping","domain":"ebay.com","cat":["IAB1-5"],"sectioncat":["IAB1-5"],"pagecat":["IAB1-5"],"page":"http://ebay.com/inte/automation/s2s/pwt_parameter_validation_muti_slot_multi_size.html?appnexus_deal_priority=6&appnexus_video_fixedbid=10&videobid=4&cat=IAB20-3","ref":"http://ebay.com/home","search":"NewCloths","mobile":1,"privacypolicy":1,"keywords":"Cloths","publisher":{"id":"5890","name":"Test Publisher","cat":["IAB1-5"],"domain":"publisher.com"},"content":{"id":"381d2e0b-548d-4f27-bfdd-e6e66f43557e","episode":1,"title":"StarWars","series":"StarWars","season":"Season3","artist":"GeorgeLucas","genre":"Action","album":"Action","isrc":"2","url":"http://www.pubmatic.com/test/","cat":["IAB1-1","IAB1-2"],"prodq":1,"videoquality":1,"context":1,"contentrating":"MPAA","userrating":"9-Stars","qagmediarating":1,"keywords":"ActionMovies","livestream":1,"sourcerelationship":1,"len":12000,"language":"en","embeddable":1,"producer":{"id":"123","name":"GaryKurtz","cat":["IAB1-5","IAB1-6"],"domain":"producer.com"}}},"device":{"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36","dnt":0,"lmt":0,"ip":"172.16.8.74","ipv6":"2001:db8::8a2e:370:7334","devicetype":1,"make":"Apple","model":"iPhone X","os":"iOS","osv":"10","hwv":"10x","h":768,"w":1366,"ppi":4096,"pxratio":1.3,"js":1,"flashver":"1.1","language":"en","carrier":"VERIZON","mccmnc":"310-005","connectiontype":2,"ifa":"EA7583CD-A667-48BC-B806-42ECB2B48606","didsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","didmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","macsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","macmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606"},"user":{"id":"45067fec-eab7-4ca0-ad3a-87b01f21846a","buyeruid":"45067fec-eab7-4ca0-ad3a-87b01f21846a","yob":1990,"gender":"M","keywords":"Movies","customdata":"StarWars"},"regs":{"coppa":0,"ext":{"gdpr":1,"us_privacy":"1YNN"}},"ext":{"wrapper":{"profileid":4444,"versionid":1,"ssauction":1,"sumry_disable":0,"clientconfig":1,"supportdeals":true}}}`), + }, + fields: fields{ + cache: mockCache, + metricEngine: mockEngine, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + "adunit@0x0": { + SlotName: "adunit@0x0", + SlotMappings: map[string]interface{}{ + models.SITE_CACHE_KEY: "12313", + models.TAG_CACHE_KEY: "45343", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"adunit@0x0"}, + HashValueMap: map[string]string{ + "adunit@0x0": "1232433543534543", + }, + }) + mockCache.EXPECT().GetPartnerConfigMap(gomock.Any(), gomock.Any(), gomock.Any()).Return(map[int]map[string]string{ + 2: { + models.PARTNER_ID: "2", + models.PREBID_PARTNER_NAME: "appnexus", + models.BidderCode: "appnexus", + models.SERVER_SIDE_FLAG: "1", + models.KEY_GEN_PATTERN: "_AU_@_W_x_H_", + models.TIMEOUT: "200", + }, + -1: { + models.DisplayVersionID: "1", + models.PLATFORM_KEY: models.PLATFORM_VIDEO, + }, + }, nil) + mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{ + ConfigPattern: "_AU_", + Config: map[string]*adunitconfig.AdConfig{ + "adunit": { + Video: &adunitconfig.Video{ + Enabled: ptrutil.ToPtr(true), + Config: &adunitconfig.VideoConfig{ + Video: openrtb2.Video{ + MIMEs: []string{"video/mp4", "video/mpeg"}, + W: ptrutil.ToPtr[int64](640), + H: ptrutil.ToPtr[int64](480), + }, + }, + UsePodConfig: ptrutil.ToPtr(true), + }, + }, + }, + }) + mockCache.EXPECT().GetAdpodConfig(gomock.Any(), gomock.Any(), gomock.Any()).Return(&adpodconfig.AdpodConfig{ + Dynamic: []adpodconfig.Dynamic{ + { + PodDur: 60, + MaxSeq: 3, + MinDuration: 20, + MaxDuration: 30, + }, + }, + Structured: []adpodconfig.Structured{ + { + MinDuration: 15, + MaxDuration: 15, + }, + }, + }, nil) + //prometheus metrics + mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "4444") + mockEngine.EXPECT().RecordPublisherRequests(models.EndpointJson, "5890", "video") + mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats("video", "5890", "appnexus") + mockEngine.EXPECT().RecordCTVRequests("json", models.PLATFORM_DISPLAY) + mockEngine.EXPECT().RecordCTVHTTPMethodRequests("json", "5890", "POST") + mockEngine.EXPECT().RecordVideoInstlImpsStats("5890", "4444") + mockEngine.EXPECT().RecordReqImpsWithContentCount("5890", models.ContentTypeSite) + mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) + mockProfileMetaData.EXPECT().GetProfileTypePlatform(gomock.Any()).Return(0, false) + }, + want: want{ + hookResult: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ + Reject: false, + NbrCode: 0, + ChangeSet: hookstage.ChangeSet[hookstage.BeforeValidationRequestPayload]{}, + DebugMessages: []string{`new imp: {"28635736ddc2bb2":{"ImpID":"28635736ddc2bb2","TagID":"adunit","Div":"","SlotName":"adunit","AdUnitName":"adunit","Secure":0,"BidFloor":1,"BidFloorCur":"USD","IsRewardInventory":null,"Banner":false,"Video":{"mimes":["video/3gpp","video/mp4"],"minduration":10,"maxduration":40,"startdelay":1,"protocols":[2,3,5,6],"w":280,"h":360,"placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"playbackend":1,"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3]},"Native":null,"IncomingSlots":["280x360"],"Type":"video","Bidders":{"appnexus":{"PartnerID":2,"PrebidBidderCode":"appnexus","MatchedSlot":"adunit@0x0","KGP":"_AU_@_W_x_H_","KGPV":"","IsRegex":false,"Params":{"placementId":0,"site":"12313","adtag":"45343"},"VASTTagFlags":null}},"NonMapped":{},"NewExt":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"}}}},"BidCtx":{},"BannerAdUnitCtx":{"MatchedSlot":"adunit","IsRegex":false,"MatchedRegex":"","SelectedSlotAdUnitConfig":{"video":{"enabled":true,"config":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"usepodconfig":true}},"AppliedSlotAdUnitConfig":{"video":{"enabled":true,"config":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"usepodconfig":true}},"UsingDefaultConfig":false,"AllowedConnectionTypes":null},"VideoAdUnitCtx":{"MatchedSlot":"adunit","IsRegex":false,"MatchedRegex":"","SelectedSlotAdUnitConfig":{"video":{"enabled":true,"config":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"usepodconfig":true}},"AppliedSlotAdUnitConfig":{"video":{"enabled":true,"config":{"mimes":["video/mp4","video/mpeg"],"w":640,"h":480},"usepodconfig":true}},"UsingDefaultConfig":false,"AllowedConnectionTypes":null},"BidderError":"","IsAdPodRequest":false,"AdpodConfig":null,"ImpAdPodCfg":null,"BidIDToAPRC":null,"AdserverURL":"","BidIDToDur":null}}`, `new request.ext: {"prebid":{"bidadjustmentfactors":{"appnexus":1},"bidderparams":{"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true,"includebrandcategory":{"primaryadserver":0,"publisher":"","withcategory":false,"translatecategories":false,"skipdedup":true}},"macros":{"[PLATFORM]":"2","[PROFILE_ID]":"4444","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}`}, + AnalyticsTags: hookanalytics.Analytics{}, + }, + bidRequest: json.RawMessage(`{"id":"1559039248176","imp":[{"id":"28635736ddc2bb2-dynamic-1-0","video":{"mimes":["video/3gpp","video/mp4"],"minduration":20,"maxduration":30,"startdelay":1,"maxseq":3,"poddur":60,"protocols":[2,3,5,6],"w":280,"h":360,"podid":"dynamic-1","placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"playbackend":1,"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3]},"displaymanager":"PubMaticSDK","displaymanagerver":"PubMaticSDK-1.0","instl":1,"tagid":"adunit","bidfloor":1,"bidfloorcur":"USD","secure":0,"iframebuster":["1"],"exp":1,"ext":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"}}}}},{"id":"28635736ddc2bb2-structured-1-1","video":{"mimes":["video/3gpp","video/mp4"],"minduration":15,"maxduration":15,"startdelay":1,"protocols":[2,3,5,6],"w":280,"h":360,"podid":"structured-1","placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"playbackend":1,"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3]},"displaymanager":"PubMaticSDK","displaymanagerver":"PubMaticSDK-1.0","instl":1,"tagid":"adunit","bidfloor":1,"bidfloorcur":"USD","secure":0,"iframebuster":["1"],"exp":1,"ext":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"}}}}}],"site":{"id":"123","name":"EbayShopping","domain":"ebay.com","cat":["IAB1-5"],"sectioncat":["IAB1-5"],"pagecat":["IAB1-5"],"page":"http://ebay.com/inte/automation/s2s/pwt_parameter_validation_muti_slot_multi_size.html?appnexus_deal_priority=6\u0026appnexus_video_fixedbid=10\u0026videobid=4\u0026cat=IAB20-3","ref":"http://ebay.com/home","search":"NewCloths","mobile":1,"privacypolicy":1,"publisher":{"id":"5890","name":"Test Publisher","cat":["IAB1-5"],"domain":"publisher.com"},"content":{"id":"381d2e0b-548d-4f27-bfdd-e6e66f43557e","episode":1,"title":"StarWars","series":"StarWars","season":"Season3","artist":"GeorgeLucas","genre":"Action","album":"Action","isrc":"2","producer":{"id":"123","name":"GaryKurtz","cat":["IAB1-5","IAB1-6"],"domain":"producer.com"},"url":"http://www.pubmatic.com/test/","cat":["IAB1-1","IAB1-2"],"prodq":1,"videoquality":1,"context":1,"contentrating":"MPAA","userrating":"9-Stars","qagmediarating":1,"keywords":"ActionMovies","livestream":1,"sourcerelationship":1,"len":12000,"language":"en","embeddable":1},"keywords":"Cloths"},"device":{"dnt":0,"lmt":0,"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36","ip":"172.16.8.74","ipv6":"2001:db8::8a2e:370:7334","devicetype":1,"make":"Apple","model":"iPhone X","os":"iOS","osv":"10","hwv":"10x","h":768,"w":1366,"ppi":4096,"pxratio":1.3,"js":1,"flashver":"1.1","language":"en","carrier":"VERIZON","mccmnc":"310-005","connectiontype":2,"ifa":"EA7583CD-A667-48BC-B806-42ECB2B48606","didsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","didmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","macsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","macmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606"},"user":{"id":"45067fec-eab7-4ca0-ad3a-87b01f21846a","buyeruid":"45067fec-eab7-4ca0-ad3a-87b01f21846a","yob":1990,"gender":"M","keywords":"Movies","customdata":"StarWars"},"at":1,"tmax":500,"source":{"fd":1,"tid":"1559039248176","pchain":"pchaintagid"},"regs":{"ext":{"gdpr":1,"us_privacy":"1YNN"}},"ext":{"prebid":{"bidadjustmentfactors":{"appnexus":1},"bidderparams":{"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true,"includebrandcategory":{"primaryadserver":0,"publisher":"","withcategory":false,"translatecategories":false,"skipdedup":true}},"macros":{"[PLATFORM]":"2","[PROFILE_ID]":"4444","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}}`), + error: false, + nilCurrencyConversion: false, + doMutate: true, + }, + }, + { + name: "Read_adpod_configs_from_Adrule_and_update_request_impressions_with_configs", + args: args{ + ctx: context.Background(), + moduleCtx: hookstage.ModuleInvocationContext{ + ModuleContext: hookstage.ModuleContext{ + "rctx": models.RequestCtx{ + PubID: 5890, + PubIDStr: "5890", + ProfileID: 4444, + ProfileIDStr: "4444", + DisplayID: 1, + SSAuction: 1, + Platform: "video", + Debug: true, + UA: "go-test", + IP: "127.0.0.1", + IsCTVRequest: true, + UidCookie: &http.Cookie{ + Name: "uids", + Value: `eyJ0ZW1wVUlEcyI6eyIzM2Fjcm9zcyI6eyJ1aWQiOiIxMTkxNzkxMDk5Nzc2NjEiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OTo0My4zODg4Nzk5NVoifSwiYWRmIjp7InVpZCI6IjgwNDQ2MDgzMzM3Nzg4MzkwNzgiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMS4wMzMwNTQ3MjdaIn0sImFka2VybmVsIjp7InVpZCI6IkE5MTYzNTAwNzE0OTkyOTMyOTkwIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MDkuMzczMzg1NjYyWiJ9LCJhZGtlcm5lbEFkbiI6eyJ1aWQiOiJBOTE2MzUwMDcxNDk5MjkzMjk5MCIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEzLjQzNDkyNTg5NloifSwiYWRtaXhlciI6eyJ1aWQiOiIzNjZhMTdiMTJmMjI0ZDMwOGYzZTNiOGRhOGMzYzhhMCIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA5LjU5MjkxNDgwMVoifSwiYWRueHMiOnsidWlkIjoiNDE5Mjg5ODUzMDE0NTExOTMiLCJleHBpcmVzIjoiMjAyMy0wMS0xOFQwOTo1MzowOC44MjU0NDI2NzZaIn0sImFqYSI6eyJ1aWQiOiJzMnN1aWQ2RGVmMFl0bjJveGQ1aG9zS1AxVmV3IiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTMuMjM5MTc2MDU0WiJ9LCJlcGxhbm5pbmciOnsidWlkIjoiQUoxRjBTOE5qdTdTQ0xWOSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEwLjkyOTk2MDQ3M1oifSwiZ2Ftb3NoaSI6eyJ1aWQiOiJndXNyXzM1NmFmOWIxZDhjNjQyYjQ4MmNiYWQyYjdhMjg4MTYxIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTAuNTI0MTU3MjI1WiJ9LCJncmlkIjp7InVpZCI6IjRmYzM2MjUwLWQ4NTItNDU5Yy04NzcyLTczNTZkZTE3YWI5NyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjE0LjY5NjMxNjIyN1oifSwiZ3JvdXBtIjp7InVpZCI6IjdENzVEMjVGLUZBQzktNDQzRC1CMkQxLUIxN0ZFRTExRTAyNyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjM5LjIyNjIxMjUzMloifSwiaXgiOnsidWlkIjoiWW9ORlNENlc5QkphOEh6eEdtcXlCUUFBXHUwMDI2Mjk3IiwiZXhwaXJlcyI6IjIwMjMtMDUtMzFUMDc6NTM6MzguNTU1ODI3MzU0WiJ9LCJqaXhpZSI6eyJ1aWQiOiI3MzY3MTI1MC1lODgyLTExZWMtYjUzOC0xM2FjYjdhZjBkZTQiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMi4xOTEwOTk3MzJaIn0sImxvZ2ljYWQiOnsidWlkIjoiQVZ4OVROQS11c25pa3M4QURzTHpWa3JvaDg4QUFBR0JUREh0UUEiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OTowOS40NTUxNDk2MTZaIn0sIm1lZGlhbmV0Ijp7InVpZCI6IjI5Nzg0MjM0OTI4OTU0MTAwMDBWMTAiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMy42NzIyMTUxMjhaIn0sIm1naWQiOnsidWlkIjoibTU5Z1hyN0xlX1htIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTcuMDk3MDAxNDcxWiJ9LCJuYW5vaW50ZXJhY3RpdmUiOnsidWlkIjoiNmFlYzhjMTAzNzlkY2I3ODQxMmJjODBiNmRkOWM5NzMxNzNhYjdkNzEyZTQzMWE1YTVlYTcwMzRlNTZhNThhMCIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjE2LjcxNDgwNzUwNVoifSwib25ldGFnIjp7InVpZCI6IjdPelZoVzFOeC1LOGFVak1HMG52NXVNYm5YNEFHUXZQbnVHcHFrZ3k0ckEiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OTowOS4xNDE3NDEyNjJaIn0sIm9wZW54Ijp7InVpZCI6IjVkZWNlNjIyLTBhMjMtMGRhYi0zYTI0LTVhNzcwMTBlNDU4MiIsImV4cGlyZXMiOiIyMDIzLTA1LTMxVDA3OjUyOjQ3LjE0MDQxNzM2M1oifSwicHVibWF0aWMiOnsidWlkIjoiN0Q3NUQyNUYtRkFDOS00NDNELUIyRDEtQjE3RkVFMTFFMDI3IiwiZXhwaXJlcyI6IjIwMjItMTAtMzFUMDk6MTQ6MjUuNzM3MjU2ODk5WiJ9LCJyaWNoYXVkaWVuY2UiOnsidWlkIjoiY2I2YzYzMjAtMzNlMi00Nzc0LWIxNjAtMXp6MTY1NDg0MDc0OSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA5LjUyNTA3NDE4WiJ9LCJzbWFydHlhZHMiOnsidWlkIjoiMTJhZjE1ZTQ0ZjAwZDA3NjMwZTc0YzQ5MTU0Y2JmYmE0Zjg0N2U4ZDRhMTU0YzhjM2Q1MWY1OGNmNzJhNDYyNyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEwLjgyNTAzMTg4NFoifSwic21pbGV3YW50ZWQiOnsidWlkIjoiZGQ5YzNmZTE4N2VmOWIwOWNhYTViNzExNDA0YzI4MzAiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxNC4yNTU2MDkzNjNaIn0sInN5bmFjb3JtZWRpYSI6eyJ1aWQiOiJHRFBSIiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MDkuOTc5NTgzNDM4WiJ9LCJ0cmlwbGVsaWZ0Ijp7InVpZCI6IjcwMjE5NzUwNTQ4MDg4NjUxOTQ2MyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA4Ljk4OTY3MzU3NFoifSwidmFsdWVpbXByZXNzaW9uIjp7InVpZCI6IjlkMDgxNTVmLWQ5ZmUtNGI1OC04OThlLWUyYzU2MjgyYWIzZSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjA5LjA2NzgzOTE2NFoifSwidmlzeCI6eyJ1aWQiOiIyN2UwYWMzYy1iNDZlLTQxYjMtOTkyYy1mOGQyNzE0OTQ5NWUiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxMi45ODk1MjM1NzNaIn0sInlpZWxkbGFiIjp7InVpZCI6IjY5NzE0ZDlmLWZiMDAtNGE1Zi04MTljLTRiZTE5MTM2YTMyNSIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjExLjMwMzAyNjYxNVoifSwieWllbGRtbyI6eyJ1aWQiOiJnOTZjMmY3MTlmMTU1MWIzMWY2MyIsImV4cGlyZXMiOiIyMDIyLTA2LTI0VDA1OjU5OjEwLjExMDUyODYwOVoifSwieWllbGRvbmUiOnsidWlkIjoiMmE0MmZiZDMtMmM3MC00ZWI5LWIxYmQtMDQ2OTY2NTBkOTQ4IiwiZXhwaXJlcyI6IjIwMjItMDYtMjRUMDU6NTk6MTAuMzE4MzMzOTM5WiJ9LCJ6ZXJvY2xpY2tmcmF1ZCI6eyJ1aWQiOiJiOTk5NThmZS0yYTg3LTJkYTQtOWNjNC05NjFmZDExM2JlY2UiLCJleHBpcmVzIjoiMjAyMi0wNi0yNFQwNTo1OToxNS43MTk1OTQ1NjZaIn19LCJiZGF5IjoiMjAyMi0wNS0xN1QwNjo0ODozOC4wMTc5ODgyMDZaIn0=`, + }, + KADUSERCookie: &http.Cookie{ + Name: "KADUSERCOOKIE", + Value: `7D75D25F-FAC9-443D-B2D1-B17FEE11E027`, + }, + OriginCookie: "go-test", + Endpoint: models.EndpointJson, + Method: "POST", + Aliases: make(map[string]string), + ImpBidCtx: make(map[string]models.ImpCtx), + PrebidBidderCode: make(map[string]string), + BidderResponseTimeMillis: make(map[string]int), + SeatNonBids: make(map[string][]openrtb_ext.NonBid), + MetricsEngine: mockEngine, + AdruleFlag: true, + AdpodProfileConfig: nil, + ImpAdPodConfig: make(map[string][]models.PodConfig), + }, + }, + }, + bidrequest: json.RawMessage(`{"id":"1559039248176","test":0,"at":1,"tmax":500,"source":{"fd":1,"tid":"1559039248176","pchain":"pchaintagid"},"imp":[{"id":"28635736ddc2bb2","ext":{"bidder":{"appnexus":{"keywords":[],"dealtier":{"prefix":"apnx","mindealtier":4}}}},"displaymanager":"PubMaticSDK","displaymanagerver":"PubMaticSDK-1.0","instl":1,"tagid":"adunit","bidfloor":1,"bidfloorcur":"USD","secure":0,"iframebuster":["1"],"exp":1,"video":{"mimes":["video/3gpp","video/mp4"],"minduration":10,"maxduration":40,"protocols":[2,3,5,6],"w":280,"h":360,"startdelay":1,"placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3],"playbackend":1}}],"site":{"id":"123","name":"EbayShopping","domain":"ebay.com","cat":["IAB1-5"],"sectioncat":["IAB1-5"],"pagecat":["IAB1-5"],"page":"http://ebay.com/inte/automation/s2s/pwt_parameter_validation_muti_slot_multi_size.html?appnexus_deal_priority=6&appnexus_video_fixedbid=10&videobid=4&cat=IAB20-3","ref":"http://ebay.com/home","search":"NewCloths","mobile":1,"privacypolicy":1,"keywords":"Cloths","publisher":{"id":"5890","name":"Test Publisher","cat":["IAB1-5"],"domain":"publisher.com"},"content":{"id":"381d2e0b-548d-4f27-bfdd-e6e66f43557e","episode":1,"title":"StarWars","series":"StarWars","season":"Season3","artist":"GeorgeLucas","genre":"Action","album":"Action","isrc":"2","url":"http://www.pubmatic.com/test/","cat":["IAB1-1","IAB1-2"],"prodq":1,"videoquality":1,"context":1,"contentrating":"MPAA","userrating":"9-Stars","qagmediarating":1,"keywords":"ActionMovies","livestream":1,"sourcerelationship":1,"len":12000,"language":"en","embeddable":1,"producer":{"id":"123","name":"GaryKurtz","cat":["IAB1-5","IAB1-6"],"domain":"producer.com"}}},"device":{"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36","dnt":0,"lmt":0,"ip":"172.16.8.74","ipv6":"2001:db8::8a2e:370:7334","devicetype":1,"make":"Apple","model":"iPhone X","os":"iOS","osv":"10","hwv":"10x","h":768,"w":1366,"ppi":4096,"pxratio":1.3,"js":1,"flashver":"1.1","language":"en","carrier":"VERIZON","mccmnc":"310-005","connectiontype":2,"ifa":"EA7583CD-A667-48BC-B806-42ECB2B48606","didsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","didmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","macsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","macmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606"},"user":{"id":"45067fec-eab7-4ca0-ad3a-87b01f21846a","buyeruid":"45067fec-eab7-4ca0-ad3a-87b01f21846a","yob":1990,"gender":"M","keywords":"Movies","customdata":"StarWars"},"regs":{"coppa":0,"ext":{"gdpr":1,"us_privacy":"1YNN"}},"ext":{"wrapper":{"profileid":4444,"versionid":1,"ssauction":1,"sumry_disable":0,"clientconfig":1,"supportdeals":true}}}`), + }, + fields: fields{ + cache: mockCache, + metricEngine: mockEngine, + }, + setup: func() { + mockCache.EXPECT().GetMappingsFromCacheV25(gomock.Any(), gomock.Any()).Return(map[string]models.SlotMapping{ + "adunit@0x0": { + SlotName: "adunit@0x0", + SlotMappings: map[string]interface{}{ + models.SITE_CACHE_KEY: "12313", + models.TAG_CACHE_KEY: "45343", + }, + }, + }) + mockCache.EXPECT().GetSlotToHashValueMapFromCacheV25(gomock.Any(), gomock.Any()).Return(models.SlotMappingInfo{ + OrderedSlotList: []string{"adunit@0x0"}, + HashValueMap: map[string]string{ + "adunit@0x0": "1232433543534543", + }, + }) + mockCache.EXPECT().GetPartnerConfigMap(gomock.Any(), gomock.Any(), gomock.Any()).Return(map[int]map[string]string{ + 2: { + models.PARTNER_ID: "2", + models.PREBID_PARTNER_NAME: "appnexus", + models.BidderCode: "appnexus", + models.SERVER_SIDE_FLAG: "1", + models.KEY_GEN_PATTERN: "_AU_@_W_x_H_", + models.TIMEOUT: "200", + }, + -1: { + models.DisplayVersionID: "1", + models.PLATFORM_KEY: models.PLATFORM_VIDEO, + }, + }, nil) + mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{ + ConfigPattern: "_AU_", + Config: map[string]*adunitconfig.AdConfig{ + "adunit": { + Video: &adunitconfig.Video{ + Enabled: ptrutil.ToPtr(true), + Config: &adunitconfig.VideoConfig{ + Video: openrtb2.Video{ + MIMEs: []string{"video/mp4", "video/mpeg"}, + W: ptrutil.ToPtr[int64](640), + H: ptrutil.ToPtr[int64](480), + }, + }, + }, + Adrule: []*openrtb2.Video{ + { + PodID: "dynamic-1", + PodDur: 60, + MaxSeq: 3, + MinDuration: 20, + MaxDuration: 30, + }, + { + PodID: "structured-1", + MinDuration: 15, + MaxDuration: 15, + }, + }, + }, + }, + }) + mockCache.EXPECT().GetAdpodConfig(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) + //prometheus metrics + mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "4444") + mockEngine.EXPECT().RecordPublisherRequests(models.EndpointJson, "5890", "video") + mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats("video", "5890", "appnexus") + mockEngine.EXPECT().RecordCTVRequests("json", models.PLATFORM_DISPLAY) + mockEngine.EXPECT().RecordCTVHTTPMethodRequests("json", "5890", "POST") + mockEngine.EXPECT().RecordVideoInstlImpsStats("5890", "4444") + mockEngine.EXPECT().RecordReqImpsWithContentCount("5890", models.ContentTypeSite) + mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) + mockProfileMetaData.EXPECT().GetProfileTypePlatform(gomock.Any()).Return(0, false) + }, + want: want{ + hookResult: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ + Reject: false, + NbrCode: 0, + ChangeSet: hookstage.ChangeSet[hookstage.BeforeValidationRequestPayload]{}, + DebugMessages: []string{`new imp: {"28635736ddc2bb2":{"AdpodConfig":null,"AdserverURL":"","AdUnitName":"adunit","Banner":false,"BannerAdUnitCtx":{"AllowedConnectionTypes":null,"AppliedSlotAdUnitConfig":{"adrule":[{"maxduration":30,"maxseq":3,"mimes":null,"minduration":20,"poddur":60,"podid":"dynamic-1"},{"maxduration":15,"mimes":null,"minduration":15,"podid":"structured-1"}],"video":{"config":{"h":480,"mimes":["video/mp4","video/mpeg"],"w":640},"enabled":true}},"IsRegex":false,"MatchedRegex":"","MatchedSlot":"adunit","SelectedSlotAdUnitConfig":{"adrule":[{"maxduration":30,"maxseq":3,"mimes":null,"minduration":20,"poddur":60,"podid":"dynamic-1"},{"maxduration":15,"mimes":null,"minduration":15,"podid":"structured-1"}],"video":{"config":{"h":480,"mimes":["video/mp4","video/mpeg"],"w":640},"enabled":true}},"UsingDefaultConfig":false},"BidCtx":{},"BidderError":"","Bidders":{"appnexus":{"IsRegex":false,"KGP":"_AU_@_W_x_H_","KGPV":"","MatchedSlot":"adunit@0x0","Params":{"adtag":"45343","placementId":0,"site":"12313"},"PartnerID":2,"PrebidBidderCode":"appnexus","VASTTagFlags":null}},"BidFloor":1,"BidFloorCur":"USD","BidIDToAPRC":null,"BidIDToDur":null,"Div":"","ImpAdPodCfg":null,"ImpID":"28635736ddc2bb2","IncomingSlots":["280x360"],"IsAdPodRequest":false,"IsRewardInventory":null,"Native":null,"NewExt":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"adtag":"45343","placementId":0,"site":"12313"}}}},"NonMapped":{},"Secure":0,"SlotName":"adunit","TagID":"adunit","Type":"video","Video":{"api":[1,2],"battr":[5,6,7],"companiontype":[1,2,3],"delivery":[2],"h":360,"linearity":1,"maxbitrate":2000,"maxduration":40,"maxextended":10,"mimes":["video/3gpp","video/mp4"],"minbitrate":1000,"minduration":10,"placement":5,"playbackend":1,"playbackmethod":[1],"pos":7,"protocols":[2,3,5,6],"sequence":1,"skip":1,"skipafter":10,"skipmin":5,"startdelay":1,"w":280},"VideoAdUnitCtx":{"AllowedConnectionTypes":null,"AppliedSlotAdUnitConfig":{"adrule":[{"maxduration":30,"maxseq":3,"mimes":null,"minduration":20,"poddur":60,"podid":"dynamic-1"},{"maxduration":15,"mimes":null,"minduration":15,"podid":"structured-1"}],"video":{"config":{"h":480,"mimes":["video/mp4","video/mpeg"],"w":640},"enabled":true}},"IsRegex":false,"MatchedRegex":"","MatchedSlot":"adunit","SelectedSlotAdUnitConfig":{"adrule":[{"maxduration":30,"maxseq":3,"mimes":null,"minduration":20,"poddur":60,"podid":"dynamic-1"},{"maxduration":15,"mimes":null,"minduration":15,"podid":"structured-1"}],"video":{"config":{"h":480,"mimes":["video/mp4","video/mpeg"],"w":640},"enabled":true}},"UsingDefaultConfig":false}}}`, `new request.ext: {"prebid":{"bidadjustmentfactors":{"appnexus":1},"bidderparams":{"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true,"includebrandcategory":{"primaryadserver":0,"publisher":"","withcategory":false,"translatecategories":false,"skipdedup":true}},"macros":{"[PLATFORM]":"2","[PROFILE_ID]":"4444","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}`}, + AnalyticsTags: hookanalytics.Analytics{}, + }, + bidRequest: json.RawMessage(`{"id":"1559039248176","imp":[{"id":"28635736ddc2bb2-dynamic-1-0","video":{"mimes":["video/3gpp","video/mp4"],"minduration":20,"maxduration":30,"startdelay":1,"maxseq":3,"poddur":60,"protocols":[2,3,5,6],"w":280,"h":360,"podid":"dynamic-1","placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"playbackend":1,"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3]},"displaymanager":"PubMaticSDK","displaymanagerver":"PubMaticSDK-1.0","instl":1,"tagid":"adunit","bidfloor":1,"bidfloorcur":"USD","secure":0,"iframebuster":["1"],"exp":1,"ext":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"}}}}},{"id":"28635736ddc2bb2-structured-1-1","video":{"mimes":["video/3gpp","video/mp4"],"minduration":15,"maxduration":15,"startdelay":1,"protocols":[2,3,5,6],"w":280,"h":360,"podid":"structured-1","placement":5,"linearity":1,"skip":1,"skipmin":5,"skipafter":10,"sequence":1,"battr":[5,6,7],"maxextended":10,"minbitrate":1000,"maxbitrate":2000,"playbackmethod":[1],"playbackend":1,"delivery":[2],"pos":7,"api":[1,2],"companiontype":[1,2,3]},"displaymanager":"PubMaticSDK","displaymanagerver":"PubMaticSDK-1.0","instl":1,"tagid":"adunit","bidfloor":1,"bidfloorcur":"USD","secure":0,"iframebuster":["1"],"exp":1,"ext":{"data":{"pbadslot":"adunit"},"prebid":{"bidder":{"appnexus":{"placementId":0,"site":"12313","adtag":"45343"}}}}}],"site":{"id":"123","name":"EbayShopping","domain":"ebay.com","cat":["IAB1-5"],"sectioncat":["IAB1-5"],"pagecat":["IAB1-5"],"page":"http://ebay.com/inte/automation/s2s/pwt_parameter_validation_muti_slot_multi_size.html?appnexus_deal_priority=6\u0026appnexus_video_fixedbid=10\u0026videobid=4\u0026cat=IAB20-3","ref":"http://ebay.com/home","search":"NewCloths","mobile":1,"privacypolicy":1,"publisher":{"id":"5890","name":"Test Publisher","cat":["IAB1-5"],"domain":"publisher.com"},"content":{"id":"381d2e0b-548d-4f27-bfdd-e6e66f43557e","episode":1,"title":"StarWars","series":"StarWars","season":"Season3","artist":"GeorgeLucas","genre":"Action","album":"Action","isrc":"2","producer":{"id":"123","name":"GaryKurtz","cat":["IAB1-5","IAB1-6"],"domain":"producer.com"},"url":"http://www.pubmatic.com/test/","cat":["IAB1-1","IAB1-2"],"prodq":1,"videoquality":1,"context":1,"contentrating":"MPAA","userrating":"9-Stars","qagmediarating":1,"keywords":"ActionMovies","livestream":1,"sourcerelationship":1,"len":12000,"language":"en","embeddable":1},"keywords":"Cloths"},"device":{"dnt":0,"lmt":0,"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36","ip":"172.16.8.74","ipv6":"2001:db8::8a2e:370:7334","devicetype":1,"make":"Apple","model":"iPhone X","os":"iOS","osv":"10","hwv":"10x","h":768,"w":1366,"ppi":4096,"pxratio":1.3,"js":1,"flashver":"1.1","language":"en","carrier":"VERIZON","mccmnc":"310-005","connectiontype":2,"ifa":"EA7583CD-A667-48BC-B806-42ECB2B48606","didsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","didmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","dpidmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606","macsha1":"EA7583CD-A667-48BC-B806-42ECB2B48606","macmd5":"EA7583CD-A667-48BC-B806-42ECB2B48606"},"user":{"id":"45067fec-eab7-4ca0-ad3a-87b01f21846a","buyeruid":"45067fec-eab7-4ca0-ad3a-87b01f21846a","yob":1990,"gender":"M","keywords":"Movies","customdata":"StarWars"},"at":1,"tmax":500,"source":{"fd":1,"tid":"1559039248176","pchain":"pchaintagid"},"regs":{"ext":{"gdpr":1,"us_privacy":"1YNN"}},"ext":{"prebid":{"bidadjustmentfactors":{"appnexus":1},"bidderparams":{"pubmatic":{"wiid":""}},"debug":true,"floors":{"enforcement":{"enforcepbs":true},"enabled":true},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":5,"increment":0.05},{"min":5,"max":10,"increment":0.1},{"min":10,"max":20,"increment":0.5}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true,"includebrandcategory":{"primaryadserver":0,"publisher":"","withcategory":false,"translatecategories":false,"skipdedup":true}},"macros":{"[PLATFORM]":"2","[PROFILE_ID]":"4444","[PROFILE_VERSION]":"1","[UNIX_TIMESTAMP]":"0","[WRAPPER_IMPRESSION_ID]":""}}}}`), + error: false, + nilCurrencyConversion: false, + doMutate: true, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -5664,7 +5936,7 @@ func TestGetTagID(t *testing.T) { func TestUpdateImpVideoWithVideoConfig(t *testing.T) { type args struct { imp *openrtb2.Imp - configObjInVideoConfig *modelsAdunitConfig.VideoConfig + configObjInVideoConfig *adunitconfig.VideoConfig } tests := []struct { name string @@ -5678,7 +5950,7 @@ func TestUpdateImpVideoWithVideoConfig(t *testing.T) { ID: "123", Video: &openrtb2.Video{}, }, - configObjInVideoConfig: &modelsAdunitConfig.VideoConfig{ + configObjInVideoConfig: &adunitconfig.VideoConfig{ Video: openrtb2.Video{ W: ptrutil.ToPtr[int64](300), H: ptrutil.ToPtr[int64](250), @@ -5747,7 +6019,7 @@ func TestUpdateImpVideoWithVideoConfig(t *testing.T) { }, }, - configObjInVideoConfig: &modelsAdunitConfig.VideoConfig{ + configObjInVideoConfig: &adunitconfig.VideoConfig{ Video: openrtb2.Video{ W: ptrutil.ToPtr[int64](400), H: ptrutil.ToPtr[int64](300), @@ -6155,7 +6427,7 @@ func TestIsVastUnwrapEnabled(t *testing.T) { func TestSetImpBidFloorParams(t *testing.T) { type args struct { rCtx models.RequestCtx - adUnitCfg *modelsAdunitConfig.AdConfig + adUnitCfg *adunitconfig.AdConfig imp *openrtb2.Imp conversions currency.Conversions } @@ -6171,7 +6443,7 @@ func TestSetImpBidFloorParams(t *testing.T) { rCtx: models.RequestCtx{ IsMaxFloorsEnabled: false, }, - adUnitCfg: &modelsAdunitConfig.AdConfig{ + adUnitCfg: &adunitconfig.AdConfig{ BidFloor: ptrutil.ToPtr(2.0), BidFloorCur: ptrutil.ToPtr("USD"), }, @@ -6189,7 +6461,7 @@ func TestSetImpBidFloorParams(t *testing.T) { rCtx: models.RequestCtx{ IsMaxFloorsEnabled: true, }, - adUnitCfg: &modelsAdunitConfig.AdConfig{ + adUnitCfg: &adunitconfig.AdConfig{ BidFloor: ptrutil.ToPtr(2.0), BidFloorCur: ptrutil.ToPtr("USD"), }, @@ -6207,7 +6479,7 @@ func TestSetImpBidFloorParams(t *testing.T) { rCtx: models.RequestCtx{ IsMaxFloorsEnabled: true, }, - adUnitCfg: &modelsAdunitConfig.AdConfig{ + adUnitCfg: &adunitconfig.AdConfig{ BidFloor: ptrutil.ToPtr(2.0), BidFloorCur: ptrutil.ToPtr("USD"), }, diff --git a/modules/pubmatic/openwrap/cache/gocache/adpod_config_test.go b/modules/pubmatic/openwrap/cache/gocache/adpod_config_test.go index 28a5991a44f..0763a8f05a4 100644 --- a/modules/pubmatic/openwrap/cache/gocache/adpod_config_test.go +++ b/modules/pubmatic/openwrap/cache/gocache/adpod_config_test.go @@ -63,7 +63,7 @@ func TestCachePopulateCacheWithAdpodConfig(t *testing.T) { MinDuration: 10, MaxDuration: 20, PodDur: 60, - Maxseq: 3, + MaxSeq: 3, }, }, }, nil) @@ -77,7 +77,7 @@ func TestCachePopulateCacheWithAdpodConfig(t *testing.T) { MinDuration: 10, MaxDuration: 20, PodDur: 60, - Maxseq: 3, + MaxSeq: 3, }, }, }, @@ -150,7 +150,7 @@ func TestCacheGetAdpodConfigs(t *testing.T) { MinDuration: 10, MaxDuration: 20, PodDur: 60, - Maxseq: 3, + MaxSeq: 3, }, }, }, nil) @@ -162,7 +162,7 @@ func TestCacheGetAdpodConfigs(t *testing.T) { MinDuration: 10, MaxDuration: 20, PodDur: 60, - Maxseq: 3, + MaxSeq: 3, }, }, }, @@ -214,7 +214,7 @@ func TestCacheGetAdpodConfigs(t *testing.T) { MinDuration: 30, MaxDuration: 60, PodDur: 120, - Maxseq: 4, + MaxSeq: 4, }, }, } @@ -227,7 +227,7 @@ func TestCacheGetAdpodConfigs(t *testing.T) { MinDuration: 30, MaxDuration: 60, PodDur: 120, - Maxseq: 4, + MaxSeq: 4, }, }, }, diff --git a/modules/pubmatic/openwrap/database/mysql/adpod_config_test.go b/modules/pubmatic/openwrap/database/mysql/adpod_config_test.go index 3feb5d4d2d3..8757acc794c 100644 --- a/modules/pubmatic/openwrap/database/mysql/adpod_config_test.go +++ b/modules/pubmatic/openwrap/database/mysql/adpod_config_test.go @@ -65,7 +65,7 @@ func TestMySqlDBGetAdpodConfigs(t *testing.T) { MaxDuration: 60, MinDuration: 1, PodDur: 180, - Maxseq: 5, + MaxSeq: 5, }, }, }, @@ -105,7 +105,7 @@ func TestMySqlDBGetAdpodConfigs(t *testing.T) { MaxDuration: 60, MinDuration: 1, PodDur: 180, - Maxseq: 5, + MaxSeq: 5, }, }, }, @@ -143,8 +143,8 @@ func TestMySqlDBGetAdpodConfigs(t *testing.T) { Dynamic: []adpodconfig.Dynamic{ { PodDur: 600, - Maxseq: 5, - Rqddurs: []int{6, 60, 120, 600}, + MaxSeq: 5, + RqdDurs: []int64{6, 60, 120, 600}, }, }, }, @@ -188,7 +188,7 @@ func TestMySqlDBGetAdpodConfigs(t *testing.T) { MaxDuration: 60, MinDuration: 1, PodDur: 180, - Maxseq: 5, + MaxSeq: 5, }, }, Structured: []adpodconfig.Structured{ @@ -205,8 +205,8 @@ func TestMySqlDBGetAdpodConfigs(t *testing.T) { { MaxDuration: 20, MinDuration: 5, - Maxseq: ptrutil.ToPtr(3), - PodDur: ptrutil.ToPtr(60), + MaxSeq: ptrutil.ToPtr(int64(3)), + PodDur: ptrutil.ToPtr(int64(60)), }, }, }, diff --git a/modules/pubmatic/openwrap/entrypointhook.go b/modules/pubmatic/openwrap/entrypointhook.go index 95b069bf4cf..c8d3fb5679d 100644 --- a/modules/pubmatic/openwrap/entrypointhook.go +++ b/modules/pubmatic/openwrap/entrypointhook.go @@ -112,6 +112,7 @@ func (m OpenWrap) handleEntrypointHook( LoggerImpressionID: requestExtWrapper.LoggerImpressionID, ClientConfigFlag: requestExtWrapper.ClientConfigFlag, SSAI: requestExtWrapper.SSAI, + AdruleFlag: requestExtWrapper.Video.AdruleFlag, IP: models.GetIP(payload.Request), IsCTVRequest: models.IsCTVAPIRequest(payload.Request.URL.Path), TrackerEndpoint: m.cfg.Tracker.Endpoint, @@ -136,9 +137,11 @@ func (m OpenWrap) handleEntrypointHook( SendBurl: endpoint == models.EndpointAppLovinMax || getSendBurl(payload.Body), } - // SSAuction will be always 1 for CTV request if rCtx.IsCTVRequest { + // SSAuction will be always 1 for CTV request rCtx.SSAuction = 1 + + rCtx.ImpAdPodConfig = make(map[string][]models.PodConfig) } // only http.ErrNoCookie is returned, we can ignore it diff --git a/modules/pubmatic/openwrap/models/adpod.go b/modules/pubmatic/openwrap/models/adpod.go index 4b453d0616a..83f8867a91b 100644 --- a/modules/pubmatic/openwrap/models/adpod.go +++ b/modules/pubmatic/openwrap/models/adpod.go @@ -43,3 +43,12 @@ type ImpAdPodConfig struct { MinDuration int64 `json:"minduration,omitempty"` MaxDuration int64 `json:"maxduration,omitempty"` } + +type PodConfig struct { + PodID string + PodDur int64 + MaxSeq int64 + MinDuration int64 + MaxDuration int64 + RqdDurs []int64 +} diff --git a/modules/pubmatic/openwrap/models/adpodconfig/adpodconfig.go b/modules/pubmatic/openwrap/models/adpodconfig/adpodconfig.go index 948670718ce..2da4fdda974 100644 --- a/modules/pubmatic/openwrap/models/adpodconfig/adpodconfig.go +++ b/modules/pubmatic/openwrap/models/adpodconfig/adpodconfig.go @@ -7,23 +7,23 @@ type AdpodConfig struct { } type Dynamic struct { - PodDur int `json:"poddur,omitempty"` - Maxseq int `json:"maxseq,omitempty"` - MinDuration int `json:"minduration,omitempty"` - MaxDuration int `json:"maxduration,omitempty"` - Rqddurs []int `json:"rqddurs,omitempty"` + PodDur int64 `json:"poddur,omitempty"` + MaxSeq int64 `json:"maxseq,omitempty"` + MinDuration int64 `json:"minduration,omitempty"` + MaxDuration int64 `json:"maxduration,omitempty"` + RqdDurs []int64 `json:"rqddurs,omitempty"` } type Structured struct { - MinDuration int `json:"minduration,omitempty"` - MaxDuration int `json:"maxduration,omitempty"` - Rqddurs []int `json:"rqddurs,omitempty"` + MinDuration int64 `json:"minduration,omitempty"` + MaxDuration int64 `json:"maxduration,omitempty"` + RqdDurs []int64 `json:"rqddurs,omitempty"` } type Hybrid struct { - PodDur *int `json:"poddur,omitempty"` - Maxseq *int `json:"maxseq,omitempty"` - MinDuration int `json:"minduration,omitempty"` - MaxDuration int `json:"maxduration,omitempty"` - Rqddurs []int `json:"rqddurs,omitempty"` + PodDur *int64 `json:"poddur,omitempty"` + MaxSeq *int64 `json:"maxseq,omitempty"` + MinDuration int64 `json:"minduration,omitempty"` + MaxDuration int64 `json:"maxduration,omitempty"` + RqdDurs []int64 `json:"rqddurs,omitempty"` } diff --git a/modules/pubmatic/openwrap/models/openwrap.go b/modules/pubmatic/openwrap/models/openwrap.go index 274e6ecf91a..3fa4b9c55ce 100644 --- a/modules/pubmatic/openwrap/models/openwrap.go +++ b/modules/pubmatic/openwrap/models/openwrap.go @@ -9,9 +9,13 @@ import ( "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/metrics" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/nbr" + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/ortb" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/wakanda" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/prebid/prebid-server/v2/usersync" + "github.com/prebid/prebid-server/v2/util/maputil" + "github.com/prebid/prebid-server/v2/util/ptrutil" + "github.com/prebid/prebid-server/v2/util/sliceutil" ) type RequestCtx struct { @@ -118,6 +122,16 @@ type RequestCtx struct { PriceGranularity *openrtb_ext.PriceGranularity IsMaxFloorsEnabled bool SendBurl bool + + // Adpod + AdruleFlag bool + AdpodProfileConfig *AdpodProfileConfig + ImpAdPodConfig map[string][]PodConfig +} + +type AdpodProfileConfig struct { + AdserverCreativeDurations []int `json:"videoadduration,omitempty"` //Range of ad durations allowed in the response + AdserverCreativeDurationMatchingPolicy string `json:"videoaddurationmatching,omitempty"` //Flag indicating exact ad duration requirement. (default)empty/exact/round. } type OwBid struct { @@ -168,7 +182,7 @@ type ImpCtx struct { //temp BidderError string - // CTV + // Adpod IsAdPodRequest bool AdpodConfig *AdPod ImpAdPodCfg []*ImpAdPodConfig @@ -282,3 +296,17 @@ func IsNewWinningBid(bid, wbid *OwBid, preferDeals bool) bool { bid.Nbr = nbr.LossBidLostToHigherBid.Ptr() return false } + +func (ic *ImpCtx) DeepCopy() ImpCtx { + impCtx := *ic + impCtx.IsRewardInventory = ptrutil.Clone(ic.IsRewardInventory) + impCtx.Video = ortb.DeepCopyImpVideo(ic.Video) + impCtx.Native = ortb.DeepCopyImpNative(ic.Native) + impCtx.IncomingSlots = sliceutil.Clone(ic.IncomingSlots) + impCtx.Bidders = maputil.Clone(ic.Bidders) + impCtx.NonMapped = maputil.Clone(ic.NonMapped) + impCtx.NewExt = sliceutil.Clone(ic.NewExt) + impCtx.BidCtx = maputil.Clone(ic.BidCtx) + + return impCtx +} diff --git a/modules/pubmatic/openwrap/models/request.go b/modules/pubmatic/openwrap/models/request.go index 17051bfe2b3..f6582500905 100644 --- a/modules/pubmatic/openwrap/models/request.go +++ b/modules/pubmatic/openwrap/models/request.go @@ -25,14 +25,12 @@ type ExtRequestAdPod struct { // AdPod holds Video AdPod specific extension parameters at impression level type AdPod struct { - MinAds int `json:"minads,omitempty"` //Default 1 if not specified - MaxAds int `json:"maxads,omitempty"` //Default 1 if not specified - MinDuration int `json:"adminduration,omitempty"` // (adpod.adminduration * adpod.minads) should be greater than or equal to video.minduration - MaxDuration int `json:"admaxduration,omitempty"` // (adpod.admaxduration * adpod.maxads) should be less than or equal to video.maxduration + video.maxextended - AdvertiserExclusionPercent *int `json:"excladv,omitempty"` // Percent value 0 means none of the ads can be from same advertiser 100 means can have all same advertisers - IABCategoryExclusionPercent *int `json:"excliabcat,omitempty"` // Percent value 0 means all ads should be of different IAB categories. - VideoAdDuration []int `json:"videoadduration,omitempty"` //Range of ad durations allowed in the response - VideoAdDurationMatching string `json:"videoaddurationmatching,omitempty"` //Flag indicating exact ad duration requirement. (default)empty/exact/round. + MinAds int `json:"minads,omitempty"` //Default 1 if not specified + MaxAds int `json:"maxads,omitempty"` //Default 1 if not specified + MinDuration int `json:"adminduration,omitempty"` // (adpod.adminduration * adpod.minads) should be greater than or equal to video.minduration + MaxDuration int `json:"admaxduration,omitempty"` // (adpod.admaxduration * adpod.maxads) should be less than or equal to video.maxduration + video.maxextended + AdvertiserExclusionPercent *int `json:"excladv,omitempty"` // Percent value 0 means none of the ads can be from same advertiser 100 means can have all same advertisers + IABCategoryExclusionPercent *int `json:"excliabcat,omitempty"` // Percent value 0 means all ads should be of different IAB categories. } // ImpExtension - Impression Extension @@ -109,9 +107,14 @@ type RequestExtWrapper struct { LoggerImpressionID string `json:"wiid,omitempty"` SSAI string `json:"ssai,omitempty"` KeyValues map[string]interface{} `json:"kv,omitempty"` + Video ExtRequestWrapperVideo `json:"video,omitempty"` PubId int `json:"-"` } +type ExtRequestWrapperVideo struct { + AdruleFlag bool `json:"adrule,omitempty"` +} + type BidderWrapper struct { Flag bool VASTagFlags map[string]bool diff --git a/modules/pubmatic/openwrap/ortb/imp.go b/modules/pubmatic/openwrap/ortb/imp.go new file mode 100644 index 00000000000..9a2c64aea36 --- /dev/null +++ b/modules/pubmatic/openwrap/ortb/imp.go @@ -0,0 +1,115 @@ +package ortb + +import ( + "github.com/PubMatic-OpenWrap/prebid-server/v2/util/ptrutil" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/util/sliceutil" +) + +func DeepCloneImpression(imp *openrtb2.Imp) *openrtb2.Imp { + clone := *imp + + clone.Metric = sliceutil.Clone(imp.Metric) + clone.Banner = DeepCopyImpBanner(imp.Banner) + clone.Video = DeepCopyImpVideo(imp.Video) + clone.Audio = DeepCopyImpAudio(imp.Audio) + clone.Native = DeepCopyImpNative(imp.Native) + clone.PMP = DeepCopyImpPMP(imp.PMP) + clone.ClickBrowser = ptrutil.Clone(imp.ClickBrowser) + clone.Secure = ptrutil.Clone(imp.Secure) + clone.IframeBuster = sliceutil.Clone(imp.IframeBuster) + clone.Qty = ptrutil.Clone(imp.Qty) + clone.Refresh = ptrutil.Clone(imp.Refresh) + clone.Ext = sliceutil.Clone(imp.Ext) + return &clone +} + +func DeepCopyImpVideo(video *openrtb2.Video) *openrtb2.Video { + if video == nil { + return nil + } + + videoCopy := *video + videoCopy.MIMEs = sliceutil.Clone(video.MIMEs) + videoCopy.StartDelay = ptrutil.Clone(video.StartDelay) + videoCopy.Protocols = sliceutil.Clone(video.Protocols) + videoCopy.W = ptrutil.Clone(video.W) + videoCopy.H = ptrutil.Clone(video.H) + videoCopy.RqdDurs = sliceutil.Clone(video.RqdDurs) + videoCopy.Skip = ptrutil.Clone(video.Skip) + videoCopy.BAttr = sliceutil.Clone(video.BAttr) + videoCopy.BoxingAllowed = ptrutil.Clone(video.BoxingAllowed) + videoCopy.PlaybackMethod = sliceutil.Clone(video.PlaybackMethod) + videoCopy.Delivery = sliceutil.Clone(video.Delivery) + videoCopy.Pos = ptrutil.Clone(video.Pos) + videoCopy.CompanionAd = sliceutil.Clone(video.CompanionAd) + videoCopy.API = sliceutil.Clone(video.API) + videoCopy.CompanionType = sliceutil.Clone(video.CompanionType) + videoCopy.DurFloors = sliceutil.Clone(video.DurFloors) + videoCopy.Ext = sliceutil.Clone(video.Ext) + return &videoCopy +} + +func DeepCopyImpNative(native *openrtb2.Native) *openrtb2.Native { + if native == nil { + return nil + } + + nativeCopy := *native + nativeCopy.API = sliceutil.Clone(native.API) + nativeCopy.BAttr = sliceutil.Clone(native.BAttr) + nativeCopy.Ext = sliceutil.Clone(native.Ext) + return &nativeCopy +} + +func DeepCopyImpBanner(banner *openrtb2.Banner) *openrtb2.Banner { + if banner == nil { + return nil + } + + bannerCopy := *banner + bannerCopy.Format = sliceutil.Clone(banner.Format) + bannerCopy.W = ptrutil.Clone(banner.W) + bannerCopy.H = ptrutil.Clone(banner.H) + bannerCopy.BType = sliceutil.Clone(banner.BType) + bannerCopy.BAttr = sliceutil.Clone(banner.BAttr) + bannerCopy.MIMEs = sliceutil.Clone(banner.MIMEs) + bannerCopy.ExpDir = sliceutil.Clone(banner.ExpDir) + bannerCopy.API = sliceutil.Clone(banner.API) + bannerCopy.Vcm = ptrutil.Clone(banner.Vcm) + bannerCopy.Ext = sliceutil.Clone(banner.Ext) + return &bannerCopy +} + +func DeepCopyImpAudio(audio *openrtb2.Audio) *openrtb2.Audio { + if audio == nil { + return nil + } + + audioCopy := *audio + audioCopy.MIMEs = sliceutil.Clone(audio.MIMEs) + audioCopy.Protocols = sliceutil.Clone(audio.Protocols) + audioCopy.StartDelay = ptrutil.Clone(audio.StartDelay) + audioCopy.RqdDurs = sliceutil.Clone(audio.RqdDurs) + audioCopy.BAttr = sliceutil.Clone(audio.BAttr) + audioCopy.Delivery = sliceutil.Clone(audio.Delivery) + audioCopy.CompanionAd = sliceutil.Clone(audio.CompanionAd) + audioCopy.API = sliceutil.Clone(audio.API) + audioCopy.CompanionType = sliceutil.Clone(audio.CompanionType) + audioCopy.Stitched = ptrutil.Clone(audio.Stitched) + audioCopy.NVol = ptrutil.Clone(audio.NVol) + audioCopy.DurFloors = sliceutil.Clone(audio.DurFloors) + audioCopy.Ext = sliceutil.Clone(audio.Ext) + return &audioCopy +} + +func DeepCopyImpPMP(pmp *openrtb2.PMP) *openrtb2.PMP { + if pmp == nil { + return nil + } + + pmpCopy := *pmp + pmpCopy.Deals = sliceutil.Clone(pmp.Deals) + pmpCopy.Ext = sliceutil.Clone(pmp.Ext) + return &pmpCopy +} diff --git a/modules/pubmatic/openwrap/processedauctionhook.go b/modules/pubmatic/openwrap/processedauctionhook.go index 5d381d36194..2ecc1b7c5f0 100644 --- a/modules/pubmatic/openwrap/processedauctionhook.go +++ b/modules/pubmatic/openwrap/processedauctionhook.go @@ -39,7 +39,7 @@ func (m OpenWrap) HandleProcessedAuctionHook( var imps []*openrtb_ext.ImpWrapper var errs []error if rctx.IsCTVRequest { - imps, errs = impressions.GenerateImpressions(payload.Request, rctx.ImpBidCtx, rctx.PubIDStr, m.metricEngine) + imps, errs = impressions.GenerateImpressions(payload.Request, rctx.ImpBidCtx, rctx.AdpodProfileConfig, rctx.PubIDStr, m.metricEngine) if len(errs) > 0 { for i := range errs { result.Warnings = append(result.Warnings, errs[i].Error()) From cea0feda9fd2d13e1c19b013181a2e32062379c2 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:17:17 +0530 Subject: [PATCH 05/24] Fixed import issue (#892) --- modules/pubmatic/openwrap/ortb/imp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pubmatic/openwrap/ortb/imp.go b/modules/pubmatic/openwrap/ortb/imp.go index 9a2c64aea36..9c9326678d3 100644 --- a/modules/pubmatic/openwrap/ortb/imp.go +++ b/modules/pubmatic/openwrap/ortb/imp.go @@ -1,8 +1,8 @@ package ortb import ( - "github.com/PubMatic-OpenWrap/prebid-server/v2/util/ptrutil" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/util/ptrutil" "github.com/prebid/prebid-server/v2/util/sliceutil" ) From edfbc458bb4c2c3ea078339b2f445e188a977588 Mon Sep 17 00:00:00 2001 From: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:54:33 +0530 Subject: [PATCH 06/24] UOE-8632: refactoring macro replacement in video event injection (#858) OTT-1824: using fastxml for video event injection --- adapters/vastbidder/fastxml_parser.go | 8 +- adapters/vastbidder/vastbidder.go | 4 +- endpoints/events/events_ow.go | 192 ++++ endpoints/events/events_ow_test.go | 591 +++++++++++++ endpoints/events/test/base64_vast.txt.tar.gz | Bin 0 -> 171 bytes endpoints/events/test/benchmark_results.txt | 415 +++++++++ endpoints/events/test/raw_vast.txt | 101 +++ endpoints/events/vtrack_ow.go | 376 ++++---- endpoints/events/vtrack_ow_benchmark_test.go | 68 ++ endpoints/events/vtrack_ow_test.go | 836 ++++++++---------- exchange/events.go | 27 +- exchange/events_ow.go | 37 + exchange/events_ow_test.go | 74 ++ exchange/events_test.go | 111 --- exchange/exchange.go | 7 +- exchange/exchange_ow.go | 2 +- go.mod | 6 +- go.sum | 12 +- .../pubmatic/openwrap/tracker/video_test.go | 4 +- 19 files changed, 2021 insertions(+), 850 deletions(-) create mode 100644 endpoints/events/events_ow.go create mode 100644 endpoints/events/events_ow_test.go create mode 100644 endpoints/events/test/base64_vast.txt.tar.gz create mode 100644 endpoints/events/test/benchmark_results.txt create mode 100644 endpoints/events/test/raw_vast.txt create mode 100644 endpoints/events/vtrack_ow_benchmark_test.go create mode 100644 exchange/events_ow.go create mode 100644 exchange/events_ow_test.go diff --git a/adapters/vastbidder/fastxml_parser.go b/adapters/vastbidder/fastxml_parser.go index dfbde606db7..a83cfd293f0 100644 --- a/adapters/vastbidder/fastxml_parser.go +++ b/adapters/vastbidder/fastxml_parser.go @@ -70,7 +70,7 @@ func (p *fastXMLParser) GetPricingDetails() (price float64, currency string) { return 0.0, "" } - priceValue, err := strconv.ParseFloat(strings.TrimSpace(p.reader.Text(node, true)), 64) + priceValue, err := strconv.ParseFloat(strings.TrimSpace(p.reader.RawText(node)), 64) if nil != err { return 0.0, "" } @@ -89,7 +89,7 @@ func (p *fastXMLParser) GetAdvertiser() (advertisers []string) { if p.reader.SelectAttrValue(ext, "type") == "advertiser" { ele := p.reader.SelectElement(ext, "Advertiser") if ele != nil { - if value := strings.TrimSpace(p.reader.Text(ele, true)); len(value) > 0 { + if value := strings.TrimSpace(p.reader.Text(ele)); len(value) > 0 { advertisers = append(advertisers, value) } } @@ -98,7 +98,7 @@ func (p *fastXMLParser) GetAdvertiser() (advertisers []string) { case vastVersion4x: if ele := p.reader.SelectElement(p.adElement, "Advertiser"); ele != nil { - if value := strings.TrimSpace(p.reader.Text(ele, true)); len(value) > 0 { + if value := strings.TrimSpace(p.reader.Text(ele)); len(value) > 0 { advertisers = append(advertisers, value) } } @@ -126,7 +126,7 @@ func (p *fastXMLParser) GetDuration() (int, error) { if node == nil { return 0, errEmptyVideoDuration } - return parseDuration(strings.TrimSpace(p.reader.Text(node, true))) + return parseDuration(strings.TrimSpace(p.reader.RawText(node))) } func (p *fastXMLParser) getAdElement(vast *fastxml.Element) *fastxml.Element { diff --git a/adapters/vastbidder/vastbidder.go b/adapters/vastbidder/vastbidder.go index 06b3abff67a..b6a4897f10a 100644 --- a/adapters/vastbidder/vastbidder.go +++ b/adapters/vastbidder/vastbidder.go @@ -101,13 +101,13 @@ func (a *VASTBidder) fastXMLTesting(handler *responseHandler, responseData *adap } } - vastBidderInfo := &openrtb_ext.FastXMLMetrics{ + xmlParsingMetrics := &openrtb_ext.FastXMLMetrics{ XMLParserTime: handlerTime, EtreeParserTime: etreeParserTime, IsRespMismatch: isVASTMismatch, } - responseData.FastXMLMetrics = vastBidderInfo + responseData.FastXMLMetrics = xmlParsingMetrics } // NewTagBidder is an constructor for TagBidder diff --git a/endpoints/events/events_ow.go b/endpoints/events/events_ow.go new file mode 100644 index 00000000000..00a7ba726ef --- /dev/null +++ b/endpoints/events/events_ow.go @@ -0,0 +1,192 @@ +package events + +import ( + "encoding/json" + "net/url" + "strings" + + "github.com/golang/glog" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +// standard VAST macros +// https://interactiveadvertisingbureau.github.io/vast/vast4macros/vast4-macros-latest.html#macro-spec-adcount +const ( + VASTAdTypeMacro = "[ADTYPE]" //VASTAdTypeMacro openwrap macro for ADTYPE + VASTAppBundleMacro = "[APPBUNDLE]" //VASTAppBundleMacro openwrap macro for APPBUNDLE + VASTDomainMacro = "[DOMAIN]" //VASTDomainMacro openwrap macro for DOMAIN + VASTPageURLMacro = "[PAGEURL]" //VASTPageURLMacro openwrap macro for PAGEURL + PBSEventIDMacro = "[EVENT_ID]" // PBSEventIDMacro macro for injecting PBS defined video event tracker id + PBSAccountMacro = "[PBS-ACCOUNT]" // PBSAccountMacro represents publisher id / account id + PBSBidderMacro = "[PBS-BIDDER]" // PBSBidderMacro represents bidder name + PBSOrigBidIDMacro = "[PBS-ORIG_BIDID]" // PBSOrigBidIDMacro represents original bid id. + PBSBidIDMacro = "[PBS-BIDID]" // PBSBidIDMacro represents bid id. If auction.generate-bid-id config is on, then resolve with response.seatbid.bid.ext.prebid.bidid. Else replace with response.seatbid.bid.id + PBSAdvertiserNameMacro = "[ADVERTISER_NAME]" // [ADERVERTISER_NAME] represents advertiser name + PBSAdUnitIDMacro = "[AD_UNIT]" // PBSAdUnitIDMacro Pass imp.tagId using this macro + PBSBidderCodeMacro = "[BIDDER_CODE]" // PBSBidderCodeMacro represents an alias id or core bidder id. +) + +// PubMatic specific event IDs +// This will go in event-config once PreBid modular design is in place +var trackingEventIDMap = map[string]string{ + "start": "2", + "firstQuartile": "4", + "midpoint": "3", + "thirdQuartile": "5", + "complete": "6", +} + +var trackingEvents = []string{"start", "firstQuartile", "midpoint", "thirdQuartile", "complete"} + +// GetVideoEventTracking returns map containing key as event name value as associaed video event tracking URL +// By default PBS will expect [EVENT_ID] macro in trackerURL to inject event information +// [EVENT_ID] will be injected with one of the following values +// +// firstQuartile, midpoint, thirdQuartile, complete +// +// If your company can not use [EVENT_ID] and has its own macro. provide config.TrackerMacros implementation +// and ensure that your macro is part of trackerURL configuration +// GetVideoEventTracking returns map containing key as event name value as associaed video event tracking URL +// By default PBS will expect [EVENT_ID] macro in trackerURL to inject event information +// [EVENT_ID] will be injected with one of the following values +// +// firstQuartile, midpoint, thirdQuartile, complete +// +// If your company can not use [EVENT_ID] and has its own macro. provide config.TrackerMacros implementation +// and ensure that your macro is part of trackerURL configuration +func GetVideoEventTracking( + req *openrtb2.BidRequest, + imp *openrtb2.Imp, + bid *openrtb2.Bid, + trackerURL string, + prebidGenBidId, requestingBidder, bidderCoreName string, + timestamp int64) map[string]string { + + if req == nil || imp == nil || bid == nil || strings.TrimSpace(trackerURL) == "" { + return nil + } + + // replace standard macros + // NYC shall we put all macros with their default values here? + macroMap := map[string]string{ + PBSAdUnitIDMacro: imp.TagID, + PBSBidIDMacro: bid.ID, + PBSOrigBidIDMacro: bid.ID, + PBSBidderMacro: bidderCoreName, + PBSBidderCodeMacro: requestingBidder, + PBSAdvertiserNameMacro: "", + VASTAdTypeMacro: string(openrtb_ext.BidTypeVideo), + } + + /* Use generated bidId if present, else use bid.ID */ + if len(prebidGenBidId) > 0 && prebidGenBidId != bid.ID { + macroMap[PBSBidIDMacro] = prebidGenBidId + } + + if len(bid.ADomain) > 0 { + var err error + //macroMap[PBSAdvertiserNameMacro] = strings.Join(bid.ADomain, ",") + macroMap[PBSAdvertiserNameMacro], err = extractDomain(bid.ADomain[0]) + if err != nil { + glog.Warningf("Unable to extract domain from '%s'. [%s]", bid.ADomain[0], err.Error()) + } + } + + if req.App != nil { + // macroMap[VASTAppBundleMacro] = req.App.Bundle + macroMap[VASTDomainMacro] = req.App.Bundle + if req.App.Publisher != nil { + macroMap[PBSAccountMacro] = req.App.Publisher.ID + } + } else if req.Site != nil { + macroMap[VASTDomainMacro] = getDomain(req.Site) + macroMap[VASTPageURLMacro] = req.Site.Page + if req.Site.Publisher != nil { + macroMap[PBSAccountMacro] = req.Site.Publisher.ID + } + } + + // lookup in custom macros - keep this block at last for highest priority + var reqExt openrtb_ext.ExtRequest + if req.Ext != nil { + err := json.Unmarshal(req.Ext, &reqExt) + if err != nil { + glog.Warningf("Error in unmarshling req.Ext.Prebid.Vast: [%s]", err.Error()) + } + } + for key, value := range reqExt.Prebid.Macros { + macroMap[strings.TrimSpace(key)] = strings.TrimSpace(value) + } + + eventURLMap := make(map[string]string) + for name, id := range trackingEventIDMap { // NYC check if trackingEvents and macroMap can be clubbed + // replace [EVENT_ID] macro with PBS defined event ID + macroMap[PBSEventIDMacro] = id + eventURLMap[name] = replaceMacros(trackerURL, macroMap) + } + return eventURLMap +} + +func replaceMacros(trackerURL string, macroMap map[string]string) string { + var builder strings.Builder + + for i := 0; i < len(trackerURL); i++ { + if trackerURL[i] == '[' { + found := false + j := i + 1 + for ; j < len(trackerURL); j++ { + if trackerURL[j] == ']' { + found = true + break + } + } + if found { + n := j + 1 + k := trackerURL[i:n] + if v, ok := macroMap[k]; ok { + v = url.QueryEscape(v) // NYC move QueryEscape while creating map, no need to do this everytime + _, _ = builder.Write([]byte(v)) + i = j + continue + } + } + } + _ = builder.WriteByte(trackerURL[i]) + } + + return builder.String() +} + +func extractDomain(rawURL string) (string, error) { + if !strings.HasPrefix(rawURL, "http") { + rawURL = "http://" + rawURL + } + // decode rawURL + rawURL, err := url.QueryUnescape(rawURL) + if nil != err { + return "", err + } + url, err := url.Parse(rawURL) + if nil != err { + return "", err + } + // remove www if present + return strings.TrimPrefix(url.Hostname(), "www."), nil +} + +func getDomain(site *openrtb2.Site) string { + if site.Domain != "" { + return site.Domain + } + + hostname := "" + + if site.Page != "" { + pageURL, err := url.Parse(site.Page) + if err == nil && pageURL != nil { + hostname = pageURL.Host + } + } + return hostname +} diff --git a/endpoints/events/events_ow_test.go b/endpoints/events/events_ow_test.go new file mode 100644 index 00000000000..300e3ed01b2 --- /dev/null +++ b/endpoints/events/events_ow_test.go @@ -0,0 +1,591 @@ +package events + +import ( + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/stretchr/testify/assert" +) + +func TestGetVideoEventTracking(t *testing.T) { + type args struct { + trackerURL string + bid *openrtb2.Bid + requestingBidder string + gen_bidid string + bidderCoreName string + timestamp int64 + req *openrtb2.BidRequest + } + type want struct { + trackerURLMap map[string]string + } + tests := []struct { + name string + args args + want want + }{ + { + name: "valid_scenario", + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + bid: &openrtb2.Bid{ + // AdM: vastXMLWith2Creatives, + }, + req: &openrtb2.BidRequest{ + App: &openrtb2.App{ + Bundle: "someappbundle", + }, + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=someappbundle", + "midpoint": "http://company.tracker.com?eventId=3&appbundle=someappbundle", + "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=someappbundle", + "start": "http://company.tracker.com?eventId=2&appbundle=someappbundle", + "complete": "http://company.tracker.com?eventId=6&appbundle=someappbundle"}, + }, + }, + { + name: "no_macro_value", // expect no replacement + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + App: &openrtb2.App{}, // no app bundle value + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=", + "midpoint": "http://company.tracker.com?eventId=3&appbundle=", + "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=", + "start": "http://company.tracker.com?eventId=2&appbundle=", + "complete": "http://company.tracker.com?eventId=6&appbundle="}, + }, + }, + { + name: "prefer_company_value_for_standard_macro", + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + App: &openrtb2.App{ + Bundle: "myapp", // do not expect this value + }, + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + Ext: []byte(`{"prebid":{ + "macros": { + "[DOMAIN]": "my_custom_value" + } + }}`), + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=my_custom_value", + "midpoint": "http://company.tracker.com?eventId=3&appbundle=my_custom_value", + "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=my_custom_value", + "start": "http://company.tracker.com?eventId=2&appbundle=my_custom_value", + "complete": "http://company.tracker.com?eventId=6&appbundle=my_custom_value"}, + }, + }, + { + name: "multireplace_macro", + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]¶meter2=[DOMAIN]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + App: &openrtb2.App{ + Bundle: "myapp123", + }, + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=myapp123¶meter2=myapp123", + "midpoint": "http://company.tracker.com?eventId=3&appbundle=myapp123¶meter2=myapp123", + "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=myapp123¶meter2=myapp123", + "start": "http://company.tracker.com?eventId=2&appbundle=myapp123¶meter2=myapp123", + "complete": "http://company.tracker.com?eventId=6&appbundle=myapp123¶meter2=myapp123"}, + }, + }, + { + name: "custom_macro_without_prefix_and_suffix", + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]¶m1=[CUSTOM_MACRO]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + Ext: []byte(`{"prebid":{ + "macros": { + "CUSTOM_MACRO": "my_custom_value" + } + }}`), + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4¶m1=[CUSTOM_MACRO]", + "midpoint": "http://company.tracker.com?eventId=3¶m1=[CUSTOM_MACRO]", + "thirdQuartile": "http://company.tracker.com?eventId=5¶m1=[CUSTOM_MACRO]", + "start": "http://company.tracker.com?eventId=2¶m1=[CUSTOM_MACRO]", + "complete": "http://company.tracker.com?eventId=6¶m1=[CUSTOM_MACRO]"}, + }, + }, + { + name: "empty_macro", + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]¶m1=[CUSTOM_MACRO]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + Ext: []byte(`{"prebid":{ + "macros": { + "": "my_custom_value" + } + }}`), + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4¶m1=[CUSTOM_MACRO]", + "midpoint": "http://company.tracker.com?eventId=3¶m1=[CUSTOM_MACRO]", + "thirdQuartile": "http://company.tracker.com?eventId=5¶m1=[CUSTOM_MACRO]", + "start": "http://company.tracker.com?eventId=2¶m1=[CUSTOM_MACRO]", + "complete": "http://company.tracker.com?eventId=6¶m1=[CUSTOM_MACRO]"}, + }, + }, + { + name: "macro_is_case_sensitive", + args: args{ + trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]¶m1=[CUSTOM_MACRO]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + Ext: []byte(`{"prebid":{ + "macros": { + "": "my_custom_value" + } + }}`), + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "http://company.tracker.com?eventId=4¶m1=[CUSTOM_MACRO]", + "midpoint": "http://company.tracker.com?eventId=3¶m1=[CUSTOM_MACRO]", + "thirdQuartile": "http://company.tracker.com?eventId=5¶m1=[CUSTOM_MACRO]", + "start": "http://company.tracker.com?eventId=2¶m1=[CUSTOM_MACRO]", + "complete": "http://company.tracker.com?eventId=6¶m1=[CUSTOM_MACRO]"}, + }, + }, + { + name: "empty_tracker_url", + args: args{ + trackerURL: " ", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + trackerURLMap: nil, + }, + }, + { + name: "site_domain_tracker_url", + args: args{ + trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]", + bid: &openrtb2.Bid{}, + req: &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Name: "test", + Domain: "www.test.com", + Publisher: &openrtb2.Publisher{ + ID: "5890"}, + }, + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + map[string]string{ + "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + }, + }, + }, + { + name: "site_page_tracker_url", + args: args{trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]", + bid: &openrtb2.Bid{}, req: &openrtb2.BidRequest{ + Site: &openrtb2.Site{ + Name: "test", + Page: "https://www.test.com/", + Publisher: &openrtb2.Publisher{ + ID: "5890", + }, + }, + Imp: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + }, + }, + }, + }, + want: want{ + map[string]string{ + "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + }, + }, + }, + { + name: "all_macros with generated_bidId", // expect encoding for WRAPPER_IMPRESSION_ID macro + args: args{ + trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]&origbidid=[PBS-ORIG_BIDID]&bc=[BIDDER_CODE]", + req: &openrtb2.BidRequest{ + App: &openrtb2.App{Bundle: "com.someapp.com", Publisher: &openrtb2.Publisher{ID: "5890"}}, + Ext: []byte(`{ + "prebid": { + "macros": { + "[PROFILE_ID]": "100", + "[PROFILE_VERSION]": "2", + "[UNIX_TIMESTAMP]": "1234567890", + "[PLATFORM]": "7", + "[WRAPPER_IMPRESSION_ID]": "abc~!@#$%^&&*()_+{}|:\"<>?[]\\;',./" + } + } + }`), + Imp: []openrtb2.Imp{ + { + TagID: "/testadunit/1", + ID: "imp_1", + Video: &openrtb2.Video{}, + }, + }, + }, + bid: &openrtb2.Bid{ADomain: []string{"http://a.com/32?k=v", "b.com"}, ImpID: "imp_1", ID: "test_bid_id"}, + gen_bidid: "random_bid_id", + requestingBidder: "test_bidder:234", + bidderCoreName: "test_core_bidder:234", + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234"}, + }, + }, + { + name: "all_macros with empty generated_bidId", // expect encoding for WRAPPER_IMPRESSION_ID macro + args: args{ + trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]&origbidid=[PBS-ORIG_BIDID]&bc=[BIDDER_CODE]", + req: &openrtb2.BidRequest{ + App: &openrtb2.App{ + Bundle: "com.someapp.com", + Publisher: &openrtb2.Publisher{ + ID: "5890", + }, + }, + Ext: []byte(`{ + "prebid": { + "macros": { + "[PROFILE_ID]": "100", + "[PROFILE_VERSION]": "2", + "[UNIX_TIMESTAMP]": "1234567890", + "[PLATFORM]": "7", + "[WRAPPER_IMPRESSION_ID]": "abc~!@#$%^&&*()_+{}|:\"<>?[]\\;',./" + } + } + }`), + Imp: []openrtb2.Imp{ + { + TagID: "/testadunit/1", + ID: "imp_1", + Video: &openrtb2.Video{}, + }, + }, + }, + bid: &openrtb2.Bid{ADomain: []string{"http://a.com/32?k=v", "b.com"}, ImpID: "imp_1", ID: "test_bid_id"}, + gen_bidid: "", + requestingBidder: "test_bidder:234", + bidderCoreName: "test_core_bidder:234", + }, + want: want{ + trackerURLMap: map[string]string{ + "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", + "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234"}, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + eventURLMap := GetVideoEventTracking(tc.args.req, &tc.args.req.Imp[0], tc.args.bid, tc.args.trackerURL, tc.args.gen_bidid, tc.args.requestingBidder, tc.args.bidderCoreName, tc.args.timestamp) + assert.Equal(t, tc.want.trackerURLMap, eventURLMap) + }) + } +} + +func TestExtractDomain(t *testing.T) { + testCases := []struct { + description string + url string + expectedDomain string + expectedErr error + }{ + {description: "a.com", url: "a.com", expectedDomain: "a.com", expectedErr: nil}, + {description: "a.com/123", url: "a.com/123", expectedDomain: "a.com", expectedErr: nil}, + {description: "http://a.com/123", url: "http://a.com/123", expectedDomain: "a.com", expectedErr: nil}, + {description: "https://a.com/123", url: "https://a.com/123", expectedDomain: "a.com", expectedErr: nil}, + {description: "c.b.a.com", url: "c.b.a.com", expectedDomain: "c.b.a.com", expectedErr: nil}, + {description: "url_encoded_http://c.b.a.com", url: "http%3A%2F%2Fc.b.a.com", expectedDomain: "c.b.a.com", expectedErr: nil}, + {description: "url_encoded_with_www_http://c.b.a.com", url: "http%3A%2F%2Fwww.c.b.a.com", expectedDomain: "c.b.a.com", expectedErr: nil}, + } + for _, test := range testCases { + t.Run(test.description, func(t *testing.T) { + domain, err := extractDomain(test.url) + assert.Equal(t, test.expectedDomain, domain) + assert.Equal(t, test.expectedErr, err) + }) + } +} + +// replaceMacros copied test cases from older replaceMacro(), will use gofuzzy once golang is upgraded +func Test_replaceMacros(t *testing.T) { + type args struct { + trackerURL string + macroMap map[string]string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "empty_tracker_url", + args: args{ + trackerURL: "", + macroMap: map[string]string{ + "[TEST]": "testme", + }, + }, + want: "", + }, + { + name: "tracker_url_with_macro", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "[TEST]": "testme", + }, + }, + want: "http://something.com?test=testme", + }, + { + name: "tracker_url_with_invalid_macro", + args: args{ + trackerURL: "http://something.com?test=TEST]", + macroMap: map[string]string{ + "[TEST]": "testme", + }, + }, + want: "http://something.com?test=TEST]", + }, + { + name: "tracker_url_with_repeating_macro", + args: args{ + trackerURL: "http://something.com?test=[TEST]&test1=[TEST]", + macroMap: map[string]string{ + "[TEST]": "testme", + }, + }, + want: "http://something.com?test=testme&test1=testme", + }, + { + name: "empty_macro", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "": "testme", + }, + }, + want: "http://something.com?test=[TEST]", + }, + { + name: "macro_without_[", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "TEST]": "testme", + }, + }, + want: "http://something.com?test=[TEST]", + }, + { + name: "macro_without_]", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "[TEST": "testme", + }, + }, + want: "http://something.com?test=[TEST]", + }, + { + name: "empty_value", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "[TEST]": ""}, + }, + want: "http://something.com?test=", + }, + { + name: "nested_macro_value", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "[TEST]": "[TEST][TEST]", + }, + }, + want: "http://something.com?test=%5BTEST%5D%5BTEST%5D", + }, + { + name: "url_as_macro_value", + args: args{ + trackerURL: "http://something.com?test=[TEST]", + macroMap: map[string]string{ + "[TEST]": "http://iamurl.com", + }, + }, + want: "http://something.com?test=http%3A%2F%2Fiamurl.com", + }, + // { Moved this responsiblity to GetVideoEventTracking() + // name: "macro_with_spaces", + // args: args{ + // trackerURL: "http://something.com?test=[TEST]", + // macroMap: map[string]string{ + // " [TEST] ": "http://iamurl.com", + // }, + // }, + // want: "http://something.com?test=http%3A%2F%2Fiamurl.com", + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := replaceMacros(tt.args.trackerURL, tt.args.macroMap) + assert.Equal(t, tt.want, got) + }) + } +} + +// BenchmarkGetVideoEventTracking +// +// Original: +// Running tool: /usr/local/go/bin/go test -benchmem -run=^$ -bench ^BenchmarkGetVideoEventTracking$ github.com/PubMatic-OpenWrap/prebid-server/endpoints/events + +// goos: linux +// goarch: arm64 +// pkg: github.com/PubMatic-OpenWrap/prebid-server/endpoints/events +// BenchmarkGetVideoEventTracking-8 19048 78882 ns/op 31590 B/op 128 allocs/op +// BenchmarkGetVideoEventTracking-8 27333 40491 ns/op 31589 B/op 128 allocs/op +// BenchmarkGetVideoEventTracking-8 28392 45111 ns/op 31586 B/op 128 allocs/op +// BenchmarkGetVideoEventTracking-8 18160 83581 ns/op 31585 B/op 128 allocs/op +// BenchmarkGetVideoEventTracking-8 16633 77993 ns/op 31591 B/op 128 allocs/op +// PASS +// ok github.com/PubMatic-OpenWrap/prebid-server/endpoints/events 1.807s + +// Refactored-GetVideoEventTracking: +// BenchmarkGetVideoEventTracking-8 10000 108697 ns/op 33489 B/op 131 allocs/op +// BenchmarkGetVideoEventTracking-8 10000 115349 ns/op 33489 B/op 131 allocs/op +// BenchmarkGetVideoEventTracking-8 12678 80833 ns/op 33486 B/op 131 allocs/op +// BenchmarkGetVideoEventTracking-8 18840 60841 ns/op 33493 B/op 131 allocs/op +// BenchmarkGetVideoEventTracking-8 20086 57733 ns/op 33482 B/op 131 allocs/op + +// Refactored-GetVideoEventTracking-using-replaceMacros: +// BenchmarkGetVideoEventTracking-8 65928 16866 ns/op 10434 B/op 96 allocs/op +// BenchmarkGetVideoEventTracking-8 66710 18611 ns/op 10433 B/op 96 allocs/op +// BenchmarkGetVideoEventTracking-8 66448 17244 ns/op 10433 B/op 96 allocs/op +// BenchmarkGetVideoEventTracking-8 35112 38085 ns/op 10433 B/op 96 allocs/op +// BenchmarkGetVideoEventTracking-8 40941 27584 ns/op 10434 B/op 96 allocs/op +func BenchmarkGetVideoEventTracking(b *testing.B) { + // all_macros with generated_bidId + trackerURL := "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]&origbidid=[PBS-ORIG_BIDID]&bc=[BIDDER_CODE]" + req := &openrtb2.BidRequest{ + App: &openrtb2.App{Bundle: "com.someapp.com", Publisher: &openrtb2.Publisher{ID: "5890"}}, + Ext: []byte(`{ + "prebid": { + "macros": { + "[PROFILE_ID]": "100", + "[PROFILE_VERSION]": "2", + "[UNIX_TIMESTAMP]": "1234567890", + "[PLATFORM]": "7", + "[WRAPPER_IMPRESSION_ID]": "abc~!@#$%^&&*()_+{}|:\"<>?[]\\;',./" + } + } + }`), + Imp: []openrtb2.Imp{ + {TagID: "/testadunit/1", ID: "imp_1"}, + }, + } + bid := &openrtb2.Bid{ADomain: []string{"http://a.com/32?k=v", "b.com"}, ImpID: "imp_1", ID: "test_bid_id"} + gen_bidid := "random_bid_id" + requestingBidder := "test_bidder:234" + bidderCoreName := "test_core_bidder:234" + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = GetVideoEventTracking(req, &req.Imp[0], bid, trackerURL, gen_bidid, requestingBidder, bidderCoreName, 0) + } +} diff --git a/endpoints/events/test/base64_vast.txt.tar.gz b/endpoints/events/test/base64_vast.txt.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..d2b6fb7105258b1e559d3af94a76c11ed9957d52 GIT binary patch literal 171 zcmV;c095}UiwFRxSjc7o153?IDag;vD=F4bElUMaC8@w5;4 Zfp*#`7zLwX6pR8I0s!aS2`~T%001MRIUxW5 literal 0 HcmV?d00001 diff --git a/endpoints/events/test/benchmark_results.txt b/endpoints/events/test/benchmark_results.txt new file mode 100644 index 00000000000..adc5267405e --- /dev/null +++ b/endpoints/events/test/benchmark_results.txt @@ -0,0 +1,415 @@ +NEW +--- +goos: linux +goarch: arm64 +pkg: github.com/PubMatic-OpenWrap/prebid-server/endpoints/events +BenchmarkInjectVideoEventTrackers-8 11994 99857 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108619 ns/op +BenchmarkInjectVideoEventTrackers-8 7047 162741 ns/op +BenchmarkInjectVideoEventTrackers-8 6451 156722 ns/op +BenchmarkInjectVideoEventTrackers-8 8053 149871 ns/op +BenchmarkInjectVideoEventTrackers-8 12775 95663 ns/op +BenchmarkInjectVideoEventTrackers-8 12192 98921 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 119874 ns/op +BenchmarkInjectVideoEventTrackers-8 8976 148432 ns/op +BenchmarkInjectVideoEventTrackers-8 12175 104665 ns/op +BenchmarkInjectVideoEventTrackers-8 12627 96783 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 142767 ns/op +BenchmarkInjectVideoEventTrackers-8 8652 130018 ns/op +BenchmarkInjectVideoEventTrackers-8 12621 94379 ns/op +BenchmarkInjectVideoEventTrackers-8 12541 95631 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 145282 ns/op +BenchmarkInjectVideoEventTrackers-8 12675 95240 ns/op +BenchmarkInjectVideoEventTrackers-8 12620 93739 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 140531 ns/op +BenchmarkInjectVideoEventTrackers-8 7932 134085 ns/op +BenchmarkInjectVideoEventTrackers-8 12958 94909 ns/op +BenchmarkInjectVideoEventTrackers-8 12896 100047 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 150835 ns/op +BenchmarkInjectVideoEventTrackers-8 11193 93567 ns/op +BenchmarkInjectVideoEventTrackers-8 12614 95702 ns/op +BenchmarkInjectVideoEventTrackers-8 11172 147317 ns/op +BenchmarkInjectVideoEventTrackers-8 10274 98216 ns/op +BenchmarkInjectVideoEventTrackers-8 12525 94558 ns/op +BenchmarkInjectVideoEventTrackers-8 12091 135374 ns/op +BenchmarkInjectVideoEventTrackers-8 12649 92635 ns/op +BenchmarkInjectVideoEventTrackers-8 12672 93532 ns/op +BenchmarkInjectVideoEventTrackers-8 9829 160558 ns/op +BenchmarkInjectVideoEventTrackers-8 9627 109390 ns/op +BenchmarkInjectVideoEventTrackers-8 12559 95794 ns/op +BenchmarkInjectVideoEventTrackers-8 12118 99115 ns/op +BenchmarkInjectVideoEventTrackers-8 12313 96845 ns/op +BenchmarkInjectVideoEventTrackers-8 12039 108354 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107922 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 130093 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109274 ns/op +BenchmarkInjectVideoEventTrackers-8 12277 99076 ns/op +BenchmarkInjectVideoEventTrackers-8 12220 97172 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106413 ns/op +BenchmarkInjectVideoEventTrackers-8 12284 96475 ns/op +BenchmarkInjectVideoEventTrackers-8 12369 97243 ns/op +BenchmarkInjectVideoEventTrackers-8 12033 102589 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 101835 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 111323 ns/op +BenchmarkInjectVideoEventTrackers-8 12139 102415 ns/op +BenchmarkInjectVideoEventTrackers-8 12520 99148 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102187 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103977 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 117965 ns/op +BenchmarkInjectVideoEventTrackers-8 12621 96923 ns/op +BenchmarkInjectVideoEventTrackers-8 12276 97474 ns/op +BenchmarkInjectVideoEventTrackers-8 12496 97902 ns/op +BenchmarkInjectVideoEventTrackers-8 12639 95111 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105928 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107623 ns/op +BenchmarkInjectVideoEventTrackers-8 12416 96683 ns/op +BenchmarkInjectVideoEventTrackers-8 12476 94106 ns/op +BenchmarkInjectVideoEventTrackers-8 12526 98440 ns/op +BenchmarkInjectVideoEventTrackers-8 12543 98846 ns/op +BenchmarkInjectVideoEventTrackers-8 12445 96899 ns/op +BenchmarkInjectVideoEventTrackers-8 12355 96749 ns/op +BenchmarkInjectVideoEventTrackers-8 12783 94215 ns/op +BenchmarkInjectVideoEventTrackers-8 12560 101970 ns/op +BenchmarkInjectVideoEventTrackers-8 12759 95018 ns/op +BenchmarkInjectVideoEventTrackers-8 12870 95196 ns/op +BenchmarkInjectVideoEventTrackers-8 12680 96009 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104518 ns/op +BenchmarkInjectVideoEventTrackers-8 12334 95338 ns/op +BenchmarkInjectVideoEventTrackers-8 12841 97060 ns/op +BenchmarkInjectVideoEventTrackers-8 12570 95457 ns/op +BenchmarkInjectVideoEventTrackers-8 12663 92850 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102418 ns/op +BenchmarkInjectVideoEventTrackers-8 12525 93522 ns/op +BenchmarkInjectVideoEventTrackers-8 12598 95461 ns/op +BenchmarkInjectVideoEventTrackers-8 12654 95732 ns/op +BenchmarkInjectVideoEventTrackers-8 12458 97007 ns/op +BenchmarkInjectVideoEventTrackers-8 12796 95227 ns/op +BenchmarkInjectVideoEventTrackers-8 12876 93244 ns/op +BenchmarkInjectVideoEventTrackers-8 12872 94017 ns/op +BenchmarkInjectVideoEventTrackers-8 12681 93816 ns/op +BenchmarkInjectVideoEventTrackers-8 12339 95252 ns/op +BenchmarkInjectVideoEventTrackers-8 12823 94395 ns/op +BenchmarkInjectVideoEventTrackers-8 12694 94203 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100970 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 113119 ns/op +BenchmarkInjectVideoEventTrackers-8 12094 94384 ns/op +BenchmarkInjectVideoEventTrackers-8 12213 99525 ns/op +BenchmarkInjectVideoEventTrackers-8 12580 93890 ns/op +BenchmarkInjectVideoEventTrackers-8 12214 92876 ns/op +BenchmarkInjectVideoEventTrackers-8 12493 95199 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102603 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102531 ns/op +BenchmarkInjectVideoEventTrackers-8 11844 96529 ns/op +BenchmarkInjectVideoEventTrackers-8 11839 98682 ns/op +BenchmarkInjectVideoEventTrackers-8 12073 95432 ns/op +BenchmarkInjectVideoEventTrackers-8 12178 93536 ns/op +BenchmarkInjectVideoEventTrackers-8 12308 95322 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106285 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107198 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 127930 ns/op +BenchmarkInjectVideoEventTrackers-8 11570 100564 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103107 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100232 ns/op +BenchmarkInjectVideoEventTrackers-8 12183 98138 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 101463 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100976 ns/op +BenchmarkInjectVideoEventTrackers-8 12136 101379 ns/op +BenchmarkInjectVideoEventTrackers-8 12129 97470 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 101763 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105143 ns/op +BenchmarkInjectVideoEventTrackers-8 12036 96395 ns/op +BenchmarkInjectVideoEventTrackers-8 12370 103113 ns/op +BenchmarkInjectVideoEventTrackers-8 12097 104316 ns/op +BenchmarkInjectVideoEventTrackers-8 10578 102399 ns/op +BenchmarkInjectVideoEventTrackers-8 12114 98435 ns/op +BenchmarkInjectVideoEventTrackers-8 12199 96260 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100708 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100063 ns/op +BenchmarkInjectVideoEventTrackers-8 12259 99365 ns/op +BenchmarkInjectVideoEventTrackers-8 11527 105366 ns/op +BenchmarkInjectVideoEventTrackers-8 12170 98071 ns/op +BenchmarkInjectVideoEventTrackers-8 11662 98735 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100196 ns/op +BenchmarkInjectVideoEventTrackers-8 12100 98485 ns/op +BenchmarkInjectVideoEventTrackers-8 12154 97764 ns/op +BenchmarkInjectVideoEventTrackers-8 12190 98722 ns/op +BenchmarkInjectVideoEventTrackers-8 12804 93210 ns/op +BenchmarkInjectVideoEventTrackers-8 12298 91861 ns/op +BenchmarkInjectVideoEventTrackers-8 12411 97100 ns/op +BenchmarkInjectVideoEventTrackers-8 12403 95998 ns/op +BenchmarkInjectVideoEventTrackers-8 12729 93676 ns/op +BenchmarkInjectVideoEventTrackers-8 12483 116678 ns/op +BenchmarkInjectVideoEventTrackers-8 10972 94685 ns/op +BenchmarkInjectVideoEventTrackers-8 12343 95353 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106452 ns/op +BenchmarkInjectVideoEventTrackers-8 12540 95257 ns/op +BenchmarkInjectVideoEventTrackers-8 12612 97109 ns/op +BenchmarkInjectVideoEventTrackers-8 12655 95869 ns/op +BenchmarkInjectVideoEventTrackers-8 12564 101473 ns/op +BenchmarkInjectVideoEventTrackers-8 12268 95826 ns/op +BenchmarkInjectVideoEventTrackers-8 12158 95248 ns/op +BenchmarkInjectVideoEventTrackers-8 12248 93556 ns/op +BenchmarkInjectVideoEventTrackers-8 12874 95673 ns/op +BenchmarkInjectVideoEventTrackers-8 12544 98246 ns/op +BenchmarkInjectVideoEventTrackers-8 12751 95809 ns/op +BenchmarkInjectVideoEventTrackers-8 12650 94296 ns/op +BenchmarkInjectVideoEventTrackers-8 12152 98760 ns/op +BenchmarkInjectVideoEventTrackers-8 12526 93759 ns/op +BenchmarkInjectVideoEventTrackers-8 12052 102301 ns/op +BenchmarkInjectVideoEventTrackers-8 12291 96482 ns/op +BenchmarkInjectVideoEventTrackers-8 12262 96106 ns/op +BenchmarkInjectVideoEventTrackers-8 12348 95109 ns/op +BenchmarkInjectVideoEventTrackers-8 12496 95862 ns/op +BenchmarkInjectVideoEventTrackers-8 12453 93967 ns/op +BenchmarkInjectVideoEventTrackers-8 12153 99390 ns/op +BenchmarkInjectVideoEventTrackers-8 12423 95374 ns/op +BenchmarkInjectVideoEventTrackers-8 12615 93599 ns/op +BenchmarkInjectVideoEventTrackers-8 12516 94149 ns/op +BenchmarkInjectVideoEventTrackers-8 12460 94459 ns/op +BenchmarkInjectVideoEventTrackers-8 12094 95090 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106277 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 142040 ns/op +BenchmarkInjectVideoEventTrackers-8 12156 94065 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100250 ns/op +BenchmarkInjectVideoEventTrackers-8 12726 96447 ns/op +BenchmarkInjectVideoEventTrackers-8 12765 102457 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 100640 ns/op +BenchmarkInjectVideoEventTrackers-8 12506 100274 ns/op +BenchmarkInjectVideoEventTrackers-8 12260 100070 ns/op +BenchmarkInjectVideoEventTrackers-8 12308 98857 ns/op +BenchmarkInjectVideoEventTrackers-8 12379 94057 ns/op +BenchmarkInjectVideoEventTrackers-8 12340 94406 ns/op +BenchmarkInjectVideoEventTrackers-8 12625 95022 ns/op +BenchmarkInjectVideoEventTrackers-8 9602 127201 ns/op +BenchmarkInjectVideoEventTrackers-8 12022 99407 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 101338 ns/op +BenchmarkInjectVideoEventTrackers-8 12512 96420 ns/op +BenchmarkInjectVideoEventTrackers-8 12604 93874 ns/op +BenchmarkInjectVideoEventTrackers-8 12098 93844 ns/op +BenchmarkInjectVideoEventTrackers-8 12193 100286 ns/op +BenchmarkInjectVideoEventTrackers-8 12698 94057 ns/op +BenchmarkInjectVideoEventTrackers-8 12655 95501 ns/op +BenchmarkInjectVideoEventTrackers-8 12780 100857 ns/op +BenchmarkInjectVideoEventTrackers-8 12702 95481 ns/op +BenchmarkInjectVideoEventTrackers-8 12699 97814 ns/op +BenchmarkInjectVideoEventTrackers-8 12127 98798 ns/op +BenchmarkInjectVideoEventTrackers-8 12010 96081 ns/op +BenchmarkInjectVideoEventTrackers-8 12501 95398 ns/op +BenchmarkInjectVideoEventTrackers-8 12560 95790 ns/op +BenchmarkInjectVideoEventTrackers-8 12624 95461 ns/op +BenchmarkInjectVideoEventTrackers-8 12519 105760 ns/op +BenchmarkInjectVideoEventTrackers-8 11209 108704 ns/op +BenchmarkInjectVideoEventTrackers-8 12322 95732 ns/op +BenchmarkInjectVideoEventTrackers-8 12771 96915 ns/op +BenchmarkInjectVideoEventTrackers-8 12816 94830 ns/op +BenchmarkInjectVideoEventTrackers-8 12598 95256 ns/op +PASS +ok github.com/PubMatic-OpenWrap/prebid-server/endpoints/events 384.888s + +OLD +--- +goos: linux +goarch: arm64 +pkg: github.com/PubMatic-OpenWrap/prebid-server/endpoints/events +BenchmarkInjectVideoEventTrackers-8 11412 103337 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103241 ns/op +BenchmarkInjectVideoEventTrackers-8 9614 107920 ns/op +BenchmarkInjectVideoEventTrackers-8 7446 142613 ns/op +BenchmarkInjectVideoEventTrackers-8 6985 152987 ns/op +BenchmarkInjectVideoEventTrackers-8 9717 113304 ns/op +BenchmarkInjectVideoEventTrackers-8 10687 111009 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103443 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 161335 ns/op +BenchmarkInjectVideoEventTrackers-8 8612 141799 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104980 ns/op +BenchmarkInjectVideoEventTrackers-8 8994 118290 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103775 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 117957 ns/op +BenchmarkInjectVideoEventTrackers-8 7485 152072 ns/op +BenchmarkInjectVideoEventTrackers-8 11416 102757 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106422 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103300 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 146524 ns/op +BenchmarkInjectVideoEventTrackers-8 11280 106079 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105962 ns/op +BenchmarkInjectVideoEventTrackers-8 11071 141065 ns/op +BenchmarkInjectVideoEventTrackers-8 9565 108086 ns/op +BenchmarkInjectVideoEventTrackers-8 9354 113106 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103729 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103996 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 157443 ns/op +BenchmarkInjectVideoEventTrackers-8 11301 111289 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104083 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102001 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 126965 ns/op +BenchmarkInjectVideoEventTrackers-8 6645 158038 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102666 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102557 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108698 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107614 ns/op +BenchmarkInjectVideoEventTrackers-8 9088 133802 ns/op +BenchmarkInjectVideoEventTrackers-8 6825 152288 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103996 ns/op +BenchmarkInjectVideoEventTrackers-8 10992 118586 ns/op +BenchmarkInjectVideoEventTrackers-8 9406 106554 ns/op +BenchmarkInjectVideoEventTrackers-8 9822 165054 ns/op +BenchmarkInjectVideoEventTrackers-8 8284 123469 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108410 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104649 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103888 ns/op +BenchmarkInjectVideoEventTrackers-8 9793 103767 ns/op +BenchmarkInjectVideoEventTrackers-8 8064 176493 ns/op +BenchmarkInjectVideoEventTrackers-8 10224 103211 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106395 ns/op +BenchmarkInjectVideoEventTrackers-8 11578 105227 ns/op +BenchmarkInjectVideoEventTrackers-8 7761 160917 ns/op +BenchmarkInjectVideoEventTrackers-8 9730 141976 ns/op +BenchmarkInjectVideoEventTrackers-8 11352 106213 ns/op +BenchmarkInjectVideoEventTrackers-8 8799 119790 ns/op +BenchmarkInjectVideoEventTrackers-8 7743 175326 ns/op +BenchmarkInjectVideoEventTrackers-8 9674 108504 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104176 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107588 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107367 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 132792 ns/op +BenchmarkInjectVideoEventTrackers-8 11179 109587 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103266 ns/op +BenchmarkInjectVideoEventTrackers-8 9483 116627 ns/op +BenchmarkInjectVideoEventTrackers-8 9438 165878 ns/op +BenchmarkInjectVideoEventTrackers-8 8343 121643 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104253 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 111989 ns/op +BenchmarkInjectVideoEventTrackers-8 11624 102501 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 163193 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102279 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103620 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102954 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104372 ns/op +BenchmarkInjectVideoEventTrackers-8 9360 121906 ns/op +BenchmarkInjectVideoEventTrackers-8 11402 102374 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102101 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103073 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105181 ns/op +BenchmarkInjectVideoEventTrackers-8 7383 171419 ns/op +BenchmarkInjectVideoEventTrackers-8 11078 105008 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102512 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106887 ns/op +BenchmarkInjectVideoEventTrackers-8 11018 174666 ns/op +BenchmarkInjectVideoEventTrackers-8 11121 104063 ns/op +BenchmarkInjectVideoEventTrackers-8 11512 113785 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108632 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103740 ns/op +BenchmarkInjectVideoEventTrackers-8 11200 104223 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109149 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102092 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104393 ns/op +BenchmarkInjectVideoEventTrackers-8 10462 104387 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107595 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108973 ns/op +BenchmarkInjectVideoEventTrackers-8 11140 104834 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 114135 ns/op +BenchmarkInjectVideoEventTrackers-8 9674 109976 ns/op +BenchmarkInjectVideoEventTrackers-8 9894 102282 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104053 ns/op +BenchmarkInjectVideoEventTrackers-8 9691 103451 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103017 ns/op +BenchmarkInjectVideoEventTrackers-8 11432 106630 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 116968 ns/op +BenchmarkInjectVideoEventTrackers-8 11148 111332 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106245 ns/op +BenchmarkInjectVideoEventTrackers-8 11107 106324 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 125663 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109025 ns/op +BenchmarkInjectVideoEventTrackers-8 9948 103579 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 111039 ns/op +BenchmarkInjectVideoEventTrackers-8 9982 107039 ns/op +BenchmarkInjectVideoEventTrackers-8 9532 119793 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108138 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107934 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107594 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103471 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103766 ns/op +BenchmarkInjectVideoEventTrackers-8 11556 101248 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 114003 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103359 ns/op +BenchmarkInjectVideoEventTrackers-8 9386 107104 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107333 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105346 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104383 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 103176 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107480 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102885 ns/op +BenchmarkInjectVideoEventTrackers-8 9937 106700 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 112205 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 114893 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104802 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 122574 ns/op +BenchmarkInjectVideoEventTrackers-8 9513 116394 ns/op +BenchmarkInjectVideoEventTrackers-8 9439 108796 ns/op +BenchmarkInjectVideoEventTrackers-8 8712 115626 ns/op +BenchmarkInjectVideoEventTrackers-8 9792 104656 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 112900 ns/op +BenchmarkInjectVideoEventTrackers-8 11197 108651 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106477 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106866 ns/op +BenchmarkInjectVideoEventTrackers-8 11379 109056 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109240 ns/op +BenchmarkInjectVideoEventTrackers-8 9552 108889 ns/op +BenchmarkInjectVideoEventTrackers-8 11392 147023 ns/op +BenchmarkInjectVideoEventTrackers-8 11553 104010 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102045 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 122656 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108962 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109847 ns/op +BenchmarkInjectVideoEventTrackers-8 9756 111888 ns/op +BenchmarkInjectVideoEventTrackers-8 11671 115049 ns/op +BenchmarkInjectVideoEventTrackers-8 9361 108008 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 108039 ns/op +BenchmarkInjectVideoEventTrackers-8 9820 107452 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104862 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 120423 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 102096 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105396 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105446 ns/op +BenchmarkInjectVideoEventTrackers-8 9808 103055 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109139 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109291 ns/op +BenchmarkInjectVideoEventTrackers-8 9427 113156 ns/op +BenchmarkInjectVideoEventTrackers-8 10416 106213 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104006 ns/op +BenchmarkInjectVideoEventTrackers-8 9496 106432 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 119959 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104761 ns/op +BenchmarkInjectVideoEventTrackers-8 9834 112330 ns/op +BenchmarkInjectVideoEventTrackers-8 9410 110560 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105160 ns/op +BenchmarkInjectVideoEventTrackers-8 9613 109464 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 104137 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106862 ns/op +BenchmarkInjectVideoEventTrackers-8 9986 107730 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105636 ns/op +BenchmarkInjectVideoEventTrackers-8 9934 113900 ns/op +BenchmarkInjectVideoEventTrackers-8 9727 119387 ns/op +BenchmarkInjectVideoEventTrackers-8 9901 123299 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 116341 ns/op +BenchmarkInjectVideoEventTrackers-8 9680 106484 ns/op +BenchmarkInjectVideoEventTrackers-8 11455 105962 ns/op +BenchmarkInjectVideoEventTrackers-8 10924 108121 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 206043 ns/op +BenchmarkInjectVideoEventTrackers-8 7663 179629 ns/op +BenchmarkInjectVideoEventTrackers-8 8349 146721 ns/op +BenchmarkInjectVideoEventTrackers-8 9888 162455 ns/op +BenchmarkInjectVideoEventTrackers-8 6970 167227 ns/op +BenchmarkInjectVideoEventTrackers-8 9943 166298 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107951 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 177137 ns/op +BenchmarkInjectVideoEventTrackers-8 11049 102284 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 106085 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 105527 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 110146 ns/op +BenchmarkInjectVideoEventTrackers-8 11310 109212 ns/op +BenchmarkInjectVideoEventTrackers-8 9882 108443 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 109327 ns/op +BenchmarkInjectVideoEventTrackers-8 10000 107013 ns/op +PASS +ok github.com/PubMatic-OpenWrap/prebid-server/endpoints/events 268.193s diff --git a/endpoints/events/test/raw_vast.txt b/endpoints/events/test/raw_vast.txt new file mode 100644 index 00000000000..2bd4a7e0d79 --- /dev/null +++ b/endpoints/events/test/raw_vast.txt @@ -0,0 +1,101 @@ +creative_url +LoopMe LTD +BidSwitch +Yahoo Ad Manager PlusVAST 2.0 Linear AdVAST 2.0 Linear Ad00:00:15 +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +\\n\\n \\n \\n \\n AdGear RTB\\n \\n \\n \\n \\n \\n \\n \\n \\n\\n +RhythmXchange Adserver +RhythmXchange Adserver +LoopMe LTD +adnxs +ebdr +RhythmXchange Adserver +RhythmXchange Adserver +BidSwitch +ebdr +ebdr +RhythmXchange Adserver +RhythmXchange Adserver +ebdr +LoopMe LTD +ebdr +RhythmXchange Adserver +PlayTime RTB +PlayTime RTB +RhythmXchange Adserver +ebdr +PlayTime RTB +GumGum +LoopMe LTD +RhythmXchange Adserver +ebdr +GumGum +RhythmXchange Adserver +ebdr +ebdr +Yahoo Ad Manager PlusVAST 2.0 Linear AdVAST 2.0 Linear Ad00:00:15 +RhythmXchange Adserver +RhythmXchange Adserver +adnxs +RhythmXchange Adserver +adnxs +adnxs +adnxs +PlayTime RTB +ebdr +BidSwitch +RhythmXchange Adserver +adnxs +RhythmXchange Adserver +ebdr +RhythmXchange Adserver +ebdr +RhythmXchange Adserver +ebdr +RhythmXchange Adserver +adnxs +MediaMath T1 VADS +adnxs +MediaMath T1 VADS +ebdr +BidSwitch +RhythmXchange Adserver +BidSwitch +Smadex +ebdr +adnxs +GumGum +RhythmXchange Adserver +RhythmXchange Adserver +ebdr +RhythmXchange Adserver +RhythmXchange Adserver +Yahoo Ad Manager PlusVAST 2.0 Linear AdVAST 2.0 Linear Ad00:02:00 +RhythmXchange Adserver +GumGum +ebdr +RhythmXchange Adserver +RTB House +ebdr +BidSwitch +Yahoo Ad Manager PlusVAST 2.0 Linear AdVAST 2.0 Linear Ad00:00:07 +ebdr +RhythmXchange Adserver +adnxs +ebdr +Yahoo Ad Manager PlusVAST 2.0 Linear AdVAST 2.0 Linear Ad00:00:07 +PlayTime RTB +RhythmXchange Adserver +RhythmXchange Adserver +RhythmXchange Adserver +RhythmXchange Adserver +RhythmXchange Adserver +ebdr +adnxs +adnxs \ No newline at end of file diff --git a/endpoints/events/vtrack_ow.go b/endpoints/events/vtrack_ow.go index 76e7ff7b707..f30e198d530 100644 --- a/endpoints/events/vtrack_ow.go +++ b/endpoints/events/vtrack_ow.go @@ -1,245 +1,214 @@ package events import ( - "encoding/json" + "bytes" "errors" - "fmt" - "net/url" "strings" + "time" + "github.com/PubMatic-OpenWrap/fastxml" "github.com/beevik/etree" - "github.com/golang/glog" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/openrtb_ext" ) -// standard VAST macros -// https://interactiveadvertisingbureau.github.io/vast/vast4macros/vast4-macros-latest.html#macro-spec-adcount -const ( - VASTAdTypeMacro = "[ADTYPE]" - VASTAppBundleMacro = "[APPBUNDLE]" - VASTDomainMacro = "[DOMAIN]" - VASTPageURLMacro = "[PAGEURL]" - - // PBS specific macros - PBSEventIDMacro = "[EVENT_ID]" // macro for injecting PBS defined video event tracker id - //[PBS-ACCOUNT] represents publisher id / account id - PBSAccountMacro = "[PBS-ACCOUNT]" - // [PBS-BIDDER] represents bidder name - PBSBidderMacro = "[PBS-BIDDER]" - // [PBS-ORIG_BIDID] represents original bid id. - PBSOrigBidIDMacro = "[PBS-ORIG_BIDID]" - // [PBS-BIDID] represents bid id. If auction.generate-bid-id config is on, then resolve with response.seatbid.bid.ext.prebid.bidid. Else replace with response.seatbid.bid.id - PBSBidIDMacro = "[PBS-BIDID]" - // [ADERVERTISER_NAME] represents advertiser name - PBSAdvertiserNameMacro = "[ADVERTISER_NAME]" - // Pass imp.tagId using this macro - PBSAdUnitIDMacro = "[AD_UNIT]" - //PBSBidderCodeMacro represents an alias id or core bidder id. - PBSBidderCodeMacro = "[BIDDER_CODE]" +var ( + errEventURLNotConfigured = errors.New("event urls not configured") ) -var trackingEvents = []string{"start", "firstQuartile", "midpoint", "thirdQuartile", "complete"} - -// PubMatic specific event IDs -// This will go in event-config once PreBid modular design is in place -var eventIDMap = map[string]string{ - "start": "2", - "firstQuartile": "4", - "midpoint": "3", - "thirdQuartile": "5", - "complete": "6", -} - // InjectVideoEventTrackers injects the video tracking events // Returns VAST xml contains as first argument. Second argument indicates whether the trackers are injected and last argument indicates if there is any error in injecting the trackers -func InjectVideoEventTrackers(trackerURL, vastXML string, bid *openrtb2.Bid, prebidGenBidId, requestingBidder, bidderCoreName, accountID string, timestamp int64, bidRequest *openrtb2.BidRequest) ([]byte, bool, error) { - // parse VAST - doc := etree.NewDocument() - err := doc.ReadFromString(vastXML) - if nil != err { - err = fmt.Errorf("account:[%s] bidder:[%s] err:[vast_xml_parsing_failed:%s] vast:[%s] ", accountID, requestingBidder, err.Error(), vastXML) - glog.Error(err.Error()) - return []byte(vastXML), false, err // false indicates events trackers are not injected - } +func InjectVideoEventTrackers( + bidRequest *openrtb2.BidRequest, + bid *openrtb2.Bid, + vastXML, trackerURL, prebidGenBidId, requestingBidder, bidderCoreName string, + timestamp int64, fastXMLExperiment bool) (response string, metrics *openrtb_ext.FastXMLMetrics, err error) { //Maintaining BidRequest Impression Map (Copied from exchange.go#applyCategoryMapping) //TODO: It should be optimized by forming once and reusing - impMap := make(map[string]*openrtb2.Imp) - for i := range bidRequest.Imp { - impMap[bidRequest.Imp[i].ID] = &bidRequest.Imp[i] + var imp *openrtb2.Imp + for _, impr := range bidRequest.Imp { + if bid.ImpID == impr.ID && impr.Video != nil { + imp = &impr + break + } + } + if imp == nil { + return vastXML, nil, nil } - eventURLMap := GetVideoEventTracking(trackerURL, bid, prebidGenBidId, requestingBidder, bidderCoreName, accountID, timestamp, bidRequest, doc, impMap) - trackersInjected := false - // return if if no tracking URL + eventURLMap := GetVideoEventTracking(bidRequest, imp, bid, trackerURL, prebidGenBidId, requestingBidder, bidderCoreName, timestamp) if len(eventURLMap) == 0 { - return []byte(vastXML), false, errors.New("Event URLs are not found") + return vastXML, nil, errEventURLNotConfigured } - creatives := FindCreatives(doc) + adm := strings.TrimSpace(bid.AdM) + nurlPresent := (adm == "" || strings.HasPrefix(adm, "http")) - if adm := strings.TrimSpace(bid.AdM); adm == "" || strings.HasPrefix(adm, "http") { - // determine which creative type to be created based on linearity - if imp, ok := impMap[bid.ImpID]; ok && nil != imp.Video { - // create creative object - creatives = doc.FindElements("VAST/Ad/Wrapper/Creatives") - // var creative *etree.Element - // if len(creatives) > 0 { - // creative = creatives[0] // consider only first creative - // } else { - creative := doc.CreateElement("Creative") - creatives[0].AddChild(creative) - - // } - - switch imp.Video.Linearity { - case adcom1.LinearityLinear: - creative.AddChild(doc.CreateElement("Linear")) - case adcom1.LinearityNonLinear: - creative.AddChild(doc.CreateElement("NonLinearAds")) - default: // create both type of creatives - creative.AddChild(doc.CreateElement("Linear")) - creative.AddChild(doc.CreateElement("NonLinearAds")) - } - creatives = creative.ChildElements() // point to actual cratives - } - } - for _, creative := range creatives { - trackingEvents := creative.SelectElement("TrackingEvents") - if nil == trackingEvents { - trackingEvents = creative.CreateElement("TrackingEvents") - creative.AddChild(trackingEvents) - } - // Inject - for event, url := range eventURLMap { - trackingEle := trackingEvents.CreateElement("Tracking") - trackingEle.CreateAttr("event", event) - trackingEle.SetText(fmt.Sprintf("%s", url)) - trackersInjected = true + _startTime := time.Now() + response, err = injectVideoEventsETree(vastXML, eventURLMap, nurlPresent, imp.Video.Linearity) + etreeParserTime := time.Since(_startTime) + + if fastXMLExperiment && err == nil { + _startTime = time.Now() + fastXMLResponse, _ := injectVideoEventsFastXML(vastXML, eventURLMap, nurlPresent, imp.Video.Linearity) + fastXMLParserTime := time.Since(_startTime) + + //temporary + if fastXMLResponse != vastXML { + fastXMLResponse = strings.ReplaceAll(fastXMLResponse, " >", ">") } - } - out := []byte(vastXML) - var wErr error - if trackersInjected { - out, wErr = doc.WriteToBytes() - trackersInjected = trackersInjected && nil == wErr - if nil != wErr { - glog.Errorf("%v", wErr.Error()) + metrics = &openrtb_ext.FastXMLMetrics{ + XMLParserTime: fastXMLParserTime, + EtreeParserTime: etreeParserTime, + IsRespMismatch: (response != fastXMLResponse), } } - return out, trackersInjected, wErr + + return response, metrics, err } -// GetVideoEventTracking returns map containing key as event name value as associaed video event tracking URL -// By default PBS will expect [EVENT_ID] macro in trackerURL to inject event information -// [EVENT_ID] will be injected with one of the following values -// -// firstQuartile, midpoint, thirdQuartile, complete -// -// If your company can not use [EVENT_ID] and has its own macro. provide config.TrackerMacros implementation -// and ensure that your macro is part of trackerURL configuration -func GetVideoEventTracking(trackerURL string, bid *openrtb2.Bid, prebidGenBidId, requestingBidder string, bidderCoreName string, accountId string, timestamp int64, req *openrtb2.BidRequest, doc *etree.Document, impMap map[string]*openrtb2.Imp) map[string]string { - eventURLMap := make(map[string]string) - if "" == strings.TrimSpace(trackerURL) { - return eventURLMap +func injectVideoEventsETree(vastXML string, eventURLMap map[string]string, nurlPresent bool, linearity adcom1.LinearityMode) (string, error) { + + // parse VAST + doc := etree.NewDocument() + if err := doc.ReadFromString(vastXML); err != nil { + return vastXML, err } - // lookup custom macros - var customMacroMap map[string]string - if nil != req.Ext { - reqExt := new(openrtb_ext.ExtRequest) - err := json.Unmarshal(req.Ext, &reqExt) - if err == nil { - customMacroMap = reqExt.Prebid.Macros - } else { - glog.Warningf("Error in unmarshling req.Ext.Prebid.Vast: [%s]", err.Error()) + doc.WriteSettings.CanonicalEndTags = true + + creatives := FindCreatives(doc) + if nurlPresent { + // create creative object + creatives = doc.FindElements("VAST/Ad/Wrapper/Creatives") + creative := doc.CreateElement("Creative") + creatives[0].AddChild(creative) + + switch linearity { + case adcom1.LinearityLinear: + creative.AddChild(doc.CreateElement("Linear")) + case adcom1.LinearityNonLinear: + creative.AddChild(doc.CreateElement("NonLinearAds")) + default: // create both type of creatives + creative.AddChild(doc.CreateElement("Linear")) + creative.AddChild(doc.CreateElement("NonLinearAds")) } + creatives = creative.ChildElements() // point to actual cratives } - for _, event := range trackingEvents { - eventURL := trackerURL - // lookup in custom macros - if nil != customMacroMap { - for customMacro, value := range customMacroMap { - eventURL = replaceMacro(eventURL, customMacro, value) - } - } - // replace standard macros - eventURL = replaceMacro(eventURL, VASTAdTypeMacro, string(openrtb_ext.BidTypeVideo)) - if nil != req && nil != req.App { - // eventURL = replaceMacro(eventURL, VASTAppBundleMacro, req.App.Bundle) - eventURL = replaceMacro(eventURL, VASTDomainMacro, req.App.Bundle) - if nil != req.App.Publisher { - eventURL = replaceMacro(eventURL, PBSAccountMacro, req.App.Publisher.ID) - } + trackersInjected := false + for _, creative := range creatives { + trackingEventsNode := creative.SelectElement("TrackingEvents") + if nil == trackingEventsNode { + trackingEventsNode = creative.CreateElement("TrackingEvents") + creative.AddChild(trackingEventsNode) } - if nil != req && nil != req.Site { - eventURL = replaceMacro(eventURL, VASTDomainMacro, getDomain(req.Site)) - eventURL = replaceMacro(eventURL, VASTPageURLMacro, req.Site.Page) - if nil != req.Site.Publisher { - eventURL = replaceMacro(eventURL, PBSAccountMacro, req.Site.Publisher.ID) + // Inject + for _, event := range trackingEvents { + if url, ok := eventURLMap[event]; ok { + trackingNode := trackingEventsNode.CreateElement("Tracking") + trackingNode.CreateAttr("event", event) + trackingNode.SetText(url) + trackersInjected = true } } + } - domain := "" - if len(bid.ADomain) > 0 { - var err error - //eventURL = replaceMacro(eventURL, PBSAdvertiserNameMacro, strings.Join(bid.ADomain, ",")) - domain, err = extractDomain(bid.ADomain[0]) - if err != nil { - glog.Warningf("Unable to extract domain from '%s'. [%s]", bid.ADomain[0], err.Error()) - } - } + if !trackersInjected { + return vastXML, nil + } + + out, err := doc.WriteToBytes() + if err != nil { + return vastXML, err + } + return string(out), nil +} + +func injectVideoEventsFastXML(vastXML string, eventURLMap map[string]string, nurlPresent bool, linearity adcom1.LinearityMode) (string, error) { - eventURL = replaceMacro(eventURL, PBSAdvertiserNameMacro, domain) + //parse vast xml + doc := fastxml.NewXMLReader(nil) + if err := doc.Parse([]byte(vastXML)); err != nil { + return vastXML, err + } + + trackersInjected := false + xu := fastxml.NewXMLUpdater(doc, fastxml.WriteSettings{ + CDATAWrap: true, + ExpandInline: true, + }) - eventURL = replaceMacro(eventURL, PBSBidderMacro, bidderCoreName) - eventURL = replaceMacro(eventURL, PBSBidderCodeMacro, requestingBidder) + if nurlPresent { + creative := doc.SelectElement(nil, "VAST", "Ad", "Wrapper", "Creatives") + if creative != nil { + cr := fastxml.CreateElement("Creative") - /* Use generated bidId if present, else use bid.ID */ - if len(prebidGenBidId) > 0 && prebidGenBidId != bid.ID { - eventURL = replaceMacro(eventURL, PBSBidIDMacro, prebidGenBidId) - } else { - eventURL = replaceMacro(eventURL, PBSBidIDMacro, bid.ID) + switch linearity { + case adcom1.LinearityLinear: + cr.AddChild(fastxml.CreateElement("Linear").AddChild(getTrackingEvents(true, eventURLMap))) + case adcom1.LinearityNonLinear: + cr.AddChild(fastxml.CreateElement("NonLinearAds").AddChild(getTrackingEvents(true, eventURLMap))) + default: + cr.AddChild(fastxml.CreateElement("Linear").AddChild(getTrackingEvents(true, eventURLMap))) + cr.AddChild(fastxml.CreateElement("NonLinearAds").AddChild(getTrackingEvents(true, eventURLMap))) + } + + xu.AppendElement(creative, cr) + trackersInjected = true } - eventURL = replaceMacro(eventURL, PBSOrigBidIDMacro, bid.ID) + } else { + // Find creatives + creatives := doc.SelectElements(nil, "VAST", "Ad", "*", "Creatives", "Creative", "*") - // replace [EVENT_ID] macro with PBS defined event ID - eventURL = replaceMacro(eventURL, PBSEventIDMacro, eventIDMap[event]) + for _, linearityElement := range creatives { + name := doc.Name(linearityElement) + if !(name == "Linear" || name == "NonLinearAds") { + continue + } - if imp, ok := impMap[bid.ImpID]; ok { - eventURL = replaceMacro(eventURL, PBSAdUnitIDMacro, imp.TagID) - } else { - glog.Warningf("Setting empty value for %s macro, as failed to determine imp.TagID for bid.ImpID: %s", PBSAdUnitIDMacro, bid.ImpID) - eventURL = replaceMacro(eventURL, PBSAdUnitIDMacro, "") + createTrackingEvents := false + parent := doc.SelectElement(linearityElement, "TrackingEvents") + if parent == nil { + createTrackingEvents = true + parent = linearityElement //Linear/NonLinearAds + } + + xu.AppendElement(parent, getTrackingEvents(createTrackingEvents, eventURLMap)) + trackersInjected = true } + } - eventURLMap[event] = eventURL + if !trackersInjected { + return vastXML, nil } - return eventURLMap + + //Add CDATA and Expand Inline Nodes + xu.ApplyXMLSettingsOperations() + + var buf bytes.Buffer + xu.Build(&buf) + return buf.String(), nil } -func replaceMacro(trackerURL, macro, value string) string { - macro = strings.TrimSpace(macro) - trimmedValue := strings.TrimSpace(value) +func getTrackingEvents(createTrackingEvents bool, eventURLMap map[string]string) *fastxml.XMLElement { + te := fastxml.CreateElement("") + if createTrackingEvents { + te.SetName("TrackingEvents") + } - if strings.HasPrefix(macro, "[") && strings.HasSuffix(macro, "]") && len(trimmedValue) > 0 { - trackerURL = strings.ReplaceAll(trackerURL, macro, url.QueryEscape(value)) - } else if strings.HasPrefix(macro, "[") && strings.HasSuffix(macro, "]") && len(trimmedValue) == 0 { - trackerURL = strings.ReplaceAll(trackerURL, macro, url.QueryEscape("")) - } else { - glog.Warningf("Invalid macro '%v'. Either empty or missing prefix '[' or suffix ']", macro) + for _, event := range trackingEvents { + if url, ok := eventURLMap[event]; ok { + tracking := fastxml.CreateElement("Tracking").AddAttribute("", "event", event).SetText(url, true, fastxml.NoEscaping) + te.AddChild(tracking) + } } - return trackerURL + return te } -// FindCreatives finds Linear, NonLinearAds fro InLine and Wrapper Type of creatives -// from input doc - VAST Document -// NOTE: This function is temporarily seperated to reuse in ctv_auction.go. Because, in case of ctv -// we generate bid.id func FindCreatives(doc *etree.Document) []*etree.Element { // Find Creatives of Linear and NonLinear Type // Injecting Tracking Events for Companion is not supported here @@ -249,36 +218,3 @@ func FindCreatives(doc *etree.Document) []*etree.Element { creatives = append(creatives, doc.FindElements("VAST/Ad/Wrapper/Creatives/Creative/NonLinearAds")...) return creatives } - -func extractDomain(rawURL string) (string, error) { - if !strings.HasPrefix(rawURL, "http") { - rawURL = "http://" + rawURL - } - // decode rawURL - rawURL, err := url.QueryUnescape(rawURL) - if nil != err { - return "", err - } - url, err := url.Parse(rawURL) - if nil != err { - return "", err - } - // remove www if present - return strings.TrimPrefix(url.Hostname(), "www."), nil -} - -func getDomain(site *openrtb2.Site) string { - if site.Domain != "" { - return site.Domain - } - - hostname := "" - - if site.Page != "" { - pageURL, err := url.Parse(site.Page) - if err == nil && pageURL != nil { - hostname = pageURL.Host - } - } - return hostname -} diff --git a/endpoints/events/vtrack_ow_benchmark_test.go b/endpoints/events/vtrack_ow_benchmark_test.go new file mode 100644 index 00000000000..4761164955f --- /dev/null +++ b/endpoints/events/vtrack_ow_benchmark_test.go @@ -0,0 +1,68 @@ +package events + +import ( + "testing" + + "github.com/prebid/openrtb/v20/adcom1" + "github.com/prebid/openrtb/v20/openrtb2" +) + +var benchMarkVAST, testVAST string +var eventURLMap map[string]string + +func init() { + benchMarkVAST = `LoopMe LTD` + + testVAST = `LoopMe LTD` + eventURLMap = map[string]string{ + "firstQuartile": "http://example.com/tracking/firstQuartile?k1=v1&k2=v2", + "midpoint": "http://example.com/tracking/midpoint", + "thirdQuartile": "http://example.com/tracking/thirdQuartile", + "complete": "http://example.com/tracking/complete", + "start": "http://company.tracker.com?eventId=2&appbundle=abc", + } +} + +func BenchmarkETreeVideoInjector(b *testing.B) { + for i := 0; i < b.N; i++ { + injectVideoEventsETree(benchMarkVAST, eventURLMap, false, adcom1.LinearityLinear) + } +} + +func BenchmarkFastXMLVideoInjector(b *testing.B) { + for i := 0; i < b.N; i++ { + injectVideoEventsFastXML(benchMarkVAST, eventURLMap, false, adcom1.LinearityLinear) + } +} + +// BenchmarkInjectVideoEventTrackers +// nilesh@9fc43242aec1: git checkout origin/ci +// nilesh@9fc43242aec1:~/go/src/github.com/PubMatic-OpenWrap/prebid-server/endpoints/events$ go test -bench=BenchmarkInjectVideoEventTrackers -count 200 -run=^# | tee old1.txt +// nilesh@9fc43242aec1: git checkout origin/UOE-8632-ci-1 +// nilesh@9fc43242aec1:~/go/src/github.com/PubMatic-OpenWrap/prebid-server/endpoints/events$ go test -bench=BenchmarkInjectVideoEventTrackers -count 200 -run=^# | tee new1.txt +// nilesh@9fc43242aec1:~/go/src/github.com/PubMatic-OpenWrap/prebid-server/endpoints/events$ benchstat old1.txt new1.txt +// goos: linux +// goarch: arm64 +// pkg: github.com/PubMatic-OpenWrap/prebid-server/endpoints/events +// +// │ old1.txt │ new1.txt │ +// │ sec/op │ sec/op vs base │ +// +// InjectVideoEventTrackers-8 107.83µ ± 1% 97.62µ ± 1% -9.47% (n=200) +func BenchmarkInjectVideoEventTrackers(b *testing.B) { + trackerURL := "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]" + vastXML := `` + bid := &openrtb2.Bid{ + AdM: ``, + } + req := &openrtb2.BidRequest{ + App: &openrtb2.App{Bundle: "abc"}, + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // no need to validate, using vast from test TestInjectVideoEventTrackers/all_inline_wrapper_liner_and_non_linear_creative + _, _, _ = InjectVideoEventTrackers(req, bid, vastXML, trackerURL, "", "test_bidder", "test_core_bidder", int64(0), false) + } +} diff --git a/endpoints/events/vtrack_ow_test.go b/endpoints/events/vtrack_ow_test.go index ac4cbbd06ac..4b7baaf39cd 100644 --- a/endpoints/events/vtrack_ow_test.go +++ b/endpoints/events/vtrack_ow_test.go @@ -1,11 +1,16 @@ package events import ( + "bufio" + "bytes" + "encoding/base64" "fmt" - "net/url" + "os" + "strings" "testing" - "github.com/beevik/etree" + "github.com/PubMatic-OpenWrap/prebid-server/v2/openrtb_ext" + "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" "github.com/stretchr/testify/assert" ) @@ -13,12 +18,15 @@ import ( func TestInjectVideoEventTrackers(t *testing.T) { type args struct { externalURL string + vastXML string genbidID string bid *openrtb2.Bid req *openrtb2.BidRequest } type want struct { - eventURLs map[string][]string + wantVastXml string + wantErr error + metrics *openrtb_ext.FastXMLMetrics } tests := []struct { name string @@ -29,608 +37,466 @@ func TestInjectVideoEventTrackers(t *testing.T) { name: "linear_creative", args: args{ externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `http://example.com/tracking/midpointhttp://example.com/tracking/thirdQuartilehttp://example.com/tracking/completehttp://partner.tracking.url`, bid: &openrtb2.Bid{ - AdM: ` - - - - http://example.com/tracking/midpoint - http://example.com/tracking/thirdQuartile - http://example.com/tracking/complete - http://partner.tracking.url - - - `, - }, - req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, + AdM: `http://example.com/tracking/midpointhttp://example.com/tracking/thirdQuartilehttp://example.com/tracking/completehttp://partner.tracking.url`, + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, }, want: want{ - eventURLs: map[string][]string{ - // "firstQuartile": {"http://example.com/tracking/firstQuartile?k1=v1&k2=v2", "http://company.tracker.com?eventId=1004&appbundle=abc"}, - // "midpoint": {"http://example.com/tracking/midpoint", "http://company.tracker.com?eventId=1003&appbundle=abc"}, - // "thirdQuartile": {"http://example.com/tracking/thirdQuartile", "http://company.tracker.com?eventId=1005&appbundle=abc"}, - // "complete": {"http://example.com/tracking/complete", "http://company.tracker.com?eventId=1006&appbundle=abc"}, - "firstQuartile": {"http://example.com/tracking/firstQuartile?k1=v1&k2=v2", "http://company.tracker.com?eventId=4&appbundle=abc"}, - "midpoint": {"http://example.com/tracking/midpoint", "http://company.tracker.com?eventId=3&appbundle=abc"}, - "thirdQuartile": {"http://example.com/tracking/thirdQuartile", "http://company.tracker.com?eventId=5&appbundle=abc"}, - "complete": {"http://example.com/tracking/complete", "http://company.tracker.com?eventId=6&appbundle=abc"}, - "start": {"http://company.tracker.com?eventId=2&appbundle=abc", "http://partner.tracking.url"}, - }, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { name: "non_linear_creative", args: args{ externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", - bid: &openrtb2.Bid{ // Adm contains to TrackingEvents tag - AdM: ` - - - http://something.com - - - `, + vastXML: `http://something.com`, + bid: &openrtb2.Bid{ + AdM: `http://something.com`, + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, + }, + want: want{ + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + }, + }, + { + name: "all_inline_wrapper_liner_and_non_linear_creative", + args: args{ + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: ``, + bid: &openrtb2.Bid{ + AdM: ``, + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, - req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, }, want: want{ - eventURLs: map[string][]string{ - // "firstQuartile": {"http://something.com", "http://company.tracker.com?eventId=1004&appbundle=abc"}, - // "midpoint": {"http://company.tracker.com?eventId=1003&appbundle=abc"}, - // "thirdQuartile": {"http://company.tracker.com?eventId=1005&appbundle=abc"}, - // "complete": {"http://company.tracker.com?eventId=1006&appbundle=abc"}, - "firstQuartile": {"http://something.com", "http://company.tracker.com?eventId=4&appbundle=abc"}, - "midpoint": {"http://company.tracker.com?eventId=3&appbundle=abc"}, - "thirdQuartile": {"http://company.tracker.com?eventId=5&appbundle=abc"}, - "complete": {"http://company.tracker.com?eventId=6&appbundle=abc"}, - "start": {"http://company.tracker.com?eventId=2&appbundle=abc"}, - }, - }, - }, { + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + }, + }, + { name: "no_traker_url_configured", // expect no injection args: args{ externalURL: "", - bid: &openrtb2.Bid{ // Adm contains to TrackingEvents tag - AdM: ` - - - `, + vastXML: ``, + bid: &openrtb2.Bid{ + AdM: ``, + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, - req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, }, want: want{ - eventURLs: map[string][]string{}, + wantVastXml: ``, + wantErr: errEventURLNotConfigured, + metrics: nil, }, }, { name: "wrapper_vast_xml_from_partner", // expect we are injecting trackers inside wrapper args: args{ externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `iabtechlabhttp://somevasturl`, bid: &openrtb2.Bid{ // Adm contains to TrackingEvents tag - AdM: ` - - - iabtechlab - http://somevasturl - - - - - - `, - }, - req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, + AdM: `iabtechlabhttp://somevasturl`, + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, }, want: want{ - eventURLs: map[string][]string{ - // "firstQuartile": {"http://company.tracker.com?eventId=firstQuartile&appbundle=abc"}, - // "midpoint": {"http://company.tracker.com?eventId=midpoint&appbundle=abc"}, - // "thirdQuartile": {"http://company.tracker.com?eventId=thirdQuartile&appbundle=abc"}, - // "complete": {"http://company.tracker.com?eventId=complete&appbundle=abc"}, - "firstQuartile": {"http://company.tracker.com?eventId=4&appbundle=abc"}, - "midpoint": {"http://company.tracker.com?eventId=3&appbundle=abc"}, - "thirdQuartile": {"http://company.tracker.com?eventId=5&appbundle=abc"}, - "complete": {"http://company.tracker.com?eventId=6&appbundle=abc"}, - "start": {"http://company.tracker.com?eventId=2&appbundle=abc"}, - }, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, - // { - // name: "vast_tag_uri_response_from_partner", - // args: args{ - // externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", - // bid: &openrtb2.Bid{ // Adm contains to TrackingEvents tag - // AdM: ``, - // }, - // req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, - // }, - // want: want{ - // eventURLs: map[string][]string{ - // "firstQuartile": {"http://company.tracker.com?eventId=firstQuartile&appbundle=abc"}, - // "midpoint": {"http://company.tracker.com?eventId=midpoint&appbundle=abc"}, - // "thirdQuartile": {"http://company.tracker.com?eventId=thirdQuartile&appbundle=abc"}, - // "complete": {"http://company.tracker.com?eventId=complete&appbundle=abc"}, - // }, - // }, - // }, - // { - // name: "adm_empty", - // args: args{ - // externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", - // bid: &openrtb2.Bid{ // Adm contains to TrackingEvents tag - // AdM: "", - // NURL: "nurl_contents", - // }, - // req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, - // }, - // want: want{ - // eventURLs: map[string][]string{ - // "firstQuartile": {"http://company.tracker.com?eventId=firstQuartile&appbundle=abc"}, - // "midpoint": {"http://company.tracker.com?eventId=midpoint&appbundle=abc"}, - // "thirdQuartile": {"http://company.tracker.com?eventId=thirdQuartile&appbundle=abc"}, - // "complete": {"http://company.tracker.com?eventId=complete&appbundle=abc"}, - // }, - // }, - // }, - } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - vast := "" - if nil != tc.args.bid { - vast = tc.args.bid.AdM // original vast - } - // bind this bid id with imp object - tc.args.req.Imp = []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}} - tc.args.bid.ImpID = tc.args.req.Imp[0].ID - accountID := "" - timestamp := int64(0) - requestingBidder := "test_bidder" - bidderCoreName := "test_core_bidder" - injectedVast, injected, ierr := InjectVideoEventTrackers(tc.args.externalURL, vast, tc.args.bid, tc.args.genbidID, requestingBidder, bidderCoreName, accountID, timestamp, tc.args.req) - - if !injected { - // expect no change in input vast if tracking events are not injected - assert.Equal(t, vast, string(injectedVast)) - assert.NotNil(t, ierr) - } else { - assert.Nil(t, ierr) - } - actualVastDoc := etree.NewDocument() - - err := actualVastDoc.ReadFromBytes(injectedVast) - if nil != err { - assert.Fail(t, err.Error()) - } - - // fmt.Println(string(injectedVast)) - actualTrackingEvents := actualVastDoc.FindElements("VAST/Ad/InLine/Creatives/Creative/Linear/TrackingEvents/Tracking") - actualTrackingEvents = append(actualTrackingEvents, actualVastDoc.FindElements("VAST/Ad/InLine/Creatives/Creative/NonLinearAds/TrackingEvents/Tracking")...) - actualTrackingEvents = append(actualTrackingEvents, actualVastDoc.FindElements("VAST/Ad/Wrapper/Creatives/Creative/Linear/TrackingEvents/Tracking")...) - actualTrackingEvents = append(actualTrackingEvents, actualVastDoc.FindElements("VAST/Ad/Wrapper/Creatives/Creative/NonLinearAds/TrackingEvents/Tracking")...) - - totalURLCount := 0 - for event, URLs := range tc.want.eventURLs { - - for _, expectedURL := range URLs { - present := false - for _, te := range actualTrackingEvents { - if te.SelectAttr("event").Value == event && te.Text() == expectedURL { - present = true - totalURLCount++ - break // expected URL present. check for next expected URL - } - } - if !present { - assert.Fail(t, "Expected tracker URL '"+expectedURL+"' is not present") - } - } - } - // ensure all total of events are injected - assert.Equal(t, totalURLCount, len(actualTrackingEvents), fmt.Sprintf("Expected '%v' event trackers. But found '%v'", len(tc.want.eventURLs), len(actualTrackingEvents))) - - }) - } -} - -func TestGetVideoEventTracking(t *testing.T) { - type args struct { - trackerURL string - bid *openrtb2.Bid - requestingBidder string - gen_bidid string - bidderCoreName string - accountId string - timestamp int64 - req *openrtb2.BidRequest - doc *etree.Document - } - type want struct { - trackerURLMap map[string]string - } - tests := []struct { - name string - args args - want want - }{ { - name: "valid_scenario", + name: "vast_tag_uri_response_from_partner", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", - bid: &openrtb2.Bid{ - // AdM: vastXMLWith2Creatives, + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: ``, + bid: &openrtb2.Bid{ + AdM: ``, }, req: &openrtb2.BidRequest{ - App: &openrtb2.App{ - Bundle: "someappbundle", - }, - Imp: []openrtb2.Imp{}, + Imp: []openrtb2.Imp{{Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile&appbundle=someappbundle", - // "midpoint": "http://company.tracker.com?eventId=midpoint&appbundle=someappbundle", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile&appbundle=someappbundle", - // "complete": "http://company.tracker.com?eventId=complete&appbundle=someappbundle"}, - "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=someappbundle", - "midpoint": "http://company.tracker.com?eventId=3&appbundle=someappbundle", - "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=someappbundle", - "start": "http://company.tracker.com?eventId=2&appbundle=someappbundle", - "complete": "http://company.tracker.com?eventId=6&appbundle=someappbundle"}, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "no_macro_value", // expect no replacement + name: "adm_empty_with_vast_build_from_modifyBidVAST", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", - bid: &openrtb2.Bid{}, + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: "", + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - App: &openrtb2.App{}, // no app bundle value - Imp: []openrtb2.Imp{}, + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile&appbundle=[DOMAIN]", - // "midpoint": "http://company.tracker.com?eventId=midpoint&appbundle=[DOMAIN]", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile&appbundle=[DOMAIN]", - // "complete": "http://company.tracker.com?eventId=complete&appbundle=[DOMAIN]"}, - "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=", - "midpoint": "http://company.tracker.com?eventId=3&appbundle=", - "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=", - "start": "http://company.tracker.com?eventId=2&appbundle=", - "complete": "http://company.tracker.com?eventId=6&appbundle="}, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "prefer_company_value_for_standard_macro", + name: "adm_empty_with_vast_build_from_modifyBidVAST_non_video", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: "", + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - App: &openrtb2.App{ - Bundle: "myapp", // do not expect this value - }, - Imp: []openrtb2.Imp{}, - Ext: []byte(`{"prebid":{ - "macros": { - "[DOMAIN]": "my_custom_value" - } - }}`), + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile&appbundle=my_custom_value", - // "midpoint": "http://company.tracker.com?eventId=midpoint&appbundle=my_custom_value", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile&appbundle=my_custom_value", - // "complete": "http://company.tracker.com?eventId=complete&appbundle=my_custom_value"}, - "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=my_custom_value", - "midpoint": "http://company.tracker.com?eventId=3&appbundle=my_custom_value", - "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=my_custom_value", - "start": "http://company.tracker.com?eventId=2&appbundle=my_custom_value", - "complete": "http://company.tracker.com?eventId=6&appbundle=my_custom_value"}, - }, - }, { - name: "multireplace_macro", + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + }, + }, + { + name: "vast_without_creative_tracking_node.Only_till_xpath_VAST/Ad/Wrapper/Creatives", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]¶meter2=[DOMAIN]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - App: &openrtb2.App{ - Bundle: "myapp123", - }, - Imp: []openrtb2.Imp{}, + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile&appbundle=myapp123¶meter2=myapp123", - // "midpoint": "http://company.tracker.com?eventId=midpoint&appbundle=myapp123¶meter2=myapp123", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile&appbundle=myapp123¶meter2=myapp123", - // "complete": "http://company.tracker.com?eventId=complete&appbundle=myapp123¶meter2=myapp123"}, - "firstQuartile": "http://company.tracker.com?eventId=4&appbundle=myapp123¶meter2=myapp123", - "midpoint": "http://company.tracker.com?eventId=3&appbundle=myapp123¶meter2=myapp123", - "thirdQuartile": "http://company.tracker.com?eventId=5&appbundle=myapp123¶meter2=myapp123", - "start": "http://company.tracker.com?eventId=2&appbundle=myapp123¶meter2=myapp123", - "complete": "http://company.tracker.com?eventId=6&appbundle=myapp123¶meter2=myapp123"}, + wantVastXml: `prebid.org wrapper`, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "custom_macro_without_prefix_and_suffix", + name: "vast_without_linear_node.Only_till_xpath_VAST/Ad/Wrapper/Creatives/Creative", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]¶m1=[CUSTOM_MACRO]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - Ext: []byte(`{"prebid":{ - "macros": { - "CUSTOM_MACRO": "my_custom_value" - } - }}`), - Imp: []openrtb2.Imp{}, + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile¶m1=[CUSTOM_MACRO]", - // "midpoint": "http://company.tracker.com?eventId=midpoint¶m1=[CUSTOM_MACRO]", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile¶m1=[CUSTOM_MACRO]", - // "complete": "http://company.tracker.com?eventId=complete¶m1=[CUSTOM_MACRO]"}, - "firstQuartile": "http://company.tracker.com?eventId=4¶m1=[CUSTOM_MACRO]", - "midpoint": "http://company.tracker.com?eventId=3¶m1=[CUSTOM_MACRO]", - "thirdQuartile": "http://company.tracker.com?eventId=5¶m1=[CUSTOM_MACRO]", - "start": "http://company.tracker.com?eventId=2¶m1=[CUSTOM_MACRO]", - "complete": "http://company.tracker.com?eventId=6¶m1=[CUSTOM_MACRO]"}, + wantVastXml: `prebid.org wrapper`, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "empty_macro", + name: "vast_without_tracking_node.Only_till_xpath_VAST/Ad/Wrapper/Creatives/Creative/Linear", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]¶m1=[CUSTOM_MACRO]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - Ext: []byte(`{"prebid":{ - "macros": { - "": "my_custom_value" - } - }}`), - Imp: []openrtb2.Imp{}, + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile¶m1=[CUSTOM_MACRO]", - // "midpoint": "http://company.tracker.com?eventId=midpoint¶m1=[CUSTOM_MACRO]", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile¶m1=[CUSTOM_MACRO]", - // "complete": "http://company.tracker.com?eventId=complete¶m1=[CUSTOM_MACRO]"}, - "firstQuartile": "http://company.tracker.com?eventId=4¶m1=[CUSTOM_MACRO]", - "midpoint": "http://company.tracker.com?eventId=3¶m1=[CUSTOM_MACRO]", - "thirdQuartile": "http://company.tracker.com?eventId=5¶m1=[CUSTOM_MACRO]", - "start": "http://company.tracker.com?eventId=2¶m1=[CUSTOM_MACRO]", - "complete": "http://company.tracker.com?eventId=6¶m1=[CUSTOM_MACRO]"}, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "macro_is_case_sensitive", + name: "vast_without_tracking_node.Only_till_xpath_VAST/Ad/Wrapper/Creatives/Creative/NonLinear", args: args{ - trackerURL: "http://company.tracker.com?eventId=[EVENT_ID]¶m1=[CUSTOM_MACRO]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - Ext: []byte(`{"prebid":{ - "macros": { - "": "my_custom_value" - } - }}`), - Imp: []openrtb2.Imp{}, + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, want: want{ - trackerURLMap: map[string]string{ - // "firstQuartile": "http://company.tracker.com?eventId=firstQuartile¶m1=[CUSTOM_MACRO]", - // "midpoint": "http://company.tracker.com?eventId=midpoint¶m1=[CUSTOM_MACRO]", - // "thirdQuartile": "http://company.tracker.com?eventId=thirdQuartile¶m1=[CUSTOM_MACRO]", - // "complete": "http://company.tracker.com?eventId=complete¶m1=[CUSTOM_MACRO]"}, - "firstQuartile": "http://company.tracker.com?eventId=4¶m1=[CUSTOM_MACRO]", - "midpoint": "http://company.tracker.com?eventId=3¶m1=[CUSTOM_MACRO]", - "thirdQuartile": "http://company.tracker.com?eventId=5¶m1=[CUSTOM_MACRO]", - "start": "http://company.tracker.com?eventId=2¶m1=[CUSTOM_MACRO]", - "complete": "http://company.tracker.com?eventId=6¶m1=[CUSTOM_MACRO]"}, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "empty_tracker_url", - args: args{trackerURL: " ", req: &openrtb2.BidRequest{Imp: []openrtb2.Imp{}}}, - want: want{trackerURLMap: make(map[string]string)}, + name: "vast_without_creative_tracking_node.Only_till_xpath_VAST/Ad/InLine/Creatives", + args: args{ + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, + }, + want: want{ + wantVastXml: `prebid.org wrapper`, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + }, }, { - name: "site_domain_tracker_url", - args: args{trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]", - req: &openrtb2.BidRequest{Site: &openrtb2.Site{Name: "test", Domain: "www.test.com", Publisher: &openrtb2.Publisher{ID: "5890"}}, Imp: []openrtb2.Imp{}}}, - want: want{ - map[string]string{ - "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + name: "vast_without_linear_node.Only_till_xpath_VAST/Ad/InLine/Creatives/Creative", + args: args{ + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, }, }, + want: want{ + wantVastXml: `prebid.org wrapper`, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + }, }, { - name: "site_page_tracker_url", - args: args{trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]", - req: &openrtb2.BidRequest{Site: &openrtb2.Site{Name: "test", Page: "https://www.test.com/", Publisher: &openrtb2.Publisher{ID: "5890"}}, Imp: []openrtb2.Imp{}}}, + name: "vast_without_tracking_node.Only_till_xpath_VAST/Ad/InLine/Creatives/Creative/Linear", + args: args{ + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", + }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, + }, want: want{ - map[string]string{ - "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", - "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=&advertiser_id=&sURL=www.test.com&pfi=[PLATFORM]&af=video&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=&bidid=", + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + }, + }, + { + name: "vast_without_tracking_node.Only_till_xpath_VAST/Ad/InLine/Creatives/Creative/NonLinear", + args: args{ + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapper`, + NURL: "nurl_contents", }, + req: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, + }, + want: want{ + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "all_macros with generated_bidId", // expect encoding for WRAPPER_IMPRESSION_ID macro + name: "vast_without_tracking_node_and_multiple_creative.All_4_xpath_Wrapper_InLine_Linear_NonLinear", args: args{ - trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]&origbidid=[PBS-ORIG_BIDID]&bc=[BIDDER_CODE]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapperprebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapperprebid.org wrapper`, + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - App: &openrtb2.App{Bundle: "com.someapp.com", Publisher: &openrtb2.Publisher{ID: "5890"}}, - Ext: []byte(`{ - "prebid": { - "macros": { - "[PROFILE_ID]": "100", - "[PROFILE_VERSION]": "2", - "[UNIX_TIMESTAMP]": "1234567890", - "[PLATFORM]": "7", - "[WRAPPER_IMPRESSION_ID]": "abc~!@#$%^&&*()_+{}|:\"<>?[]\\;',./" - } - } - }`), - Imp: []openrtb2.Imp{ - {TagID: "/testadunit/1", ID: "imp_1"}, - }, - }, - bid: &openrtb2.Bid{ADomain: []string{"http://a.com/32?k=v", "b.com"}, ImpID: "imp_1", ID: "test_bid_id"}, - gen_bidid: "random_bid_id", - requestingBidder: "test_bidder:234", - bidderCoreName: "test_core_bidder:234", + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, }, want: want{ - trackerURLMap: map[string]string{ - "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=random_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234"}, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, { - name: "all_macros with empty generated_bidId", // expect encoding for WRAPPER_IMPRESSION_ID macro + name: "vast_with_tracking_node_and_multiple_creative.All_4_xpath_Wrapper_InLine_Linear_NonLinear", args: args{ - trackerURL: "https://company.tracker.com?operId=8&e=[EVENT_ID]&p=[PBS-ACCOUNT]&pid=[PROFILE_ID]&v=[PROFILE_VERSION]&ts=[UNIX_TIMESTAMP]&pn=[PBS-BIDDER]&advertiser_id=[ADVERTISER_NAME]&sURL=[DOMAIN]&pfi=[PLATFORM]&af=[ADTYPE]&iid=[WRAPPER_IMPRESSION_ID]&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=[AD_UNIT]&bidid=[PBS-BIDID]&origbidid=[PBS-ORIG_BIDID]&bc=[BIDDER_CODE]", + externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + vastXML: `prebid.org wrapperprebid.org wrapper`, + bid: &openrtb2.Bid{ + ImpID: "123", + AdM: `prebid.org wrapperprebid.org wrapper`, + NURL: "nurl_contents", + }, req: &openrtb2.BidRequest{ - App: &openrtb2.App{Bundle: "com.someapp.com", Publisher: &openrtb2.Publisher{ID: "5890"}}, - Ext: []byte(`{ - "prebid": { - "macros": { - "[PROFILE_ID]": "100", - "[PROFILE_VERSION]": "2", - "[UNIX_TIMESTAMP]": "1234567890", - "[PLATFORM]": "7", - "[WRAPPER_IMPRESSION_ID]": "abc~!@#$%^&&*()_+{}|:\"<>?[]\\;',./" - } - } - }`), - Imp: []openrtb2.Imp{ - {TagID: "/testadunit/1", ID: "imp_1"}, - }, - }, - bid: &openrtb2.Bid{ADomain: []string{"http://a.com/32?k=v", "b.com"}, ImpID: "imp_1", ID: "test_bid_id"}, - gen_bidid: "", - requestingBidder: "test_bidder:234", - bidderCoreName: "test_core_bidder:234", + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + App: &openrtb2.App{Bundle: "abc"}, + }, }, want: want{ - trackerURLMap: map[string]string{ - "firstQuartile": "https://company.tracker.com?operId=8&e=4&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "midpoint": "https://company.tracker.com?operId=8&e=3&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "thirdQuartile": "https://company.tracker.com?operId=8&e=5&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "complete": "https://company.tracker.com?operId=8&e=6&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234", - "start": "https://company.tracker.com?operId=8&e=2&p=5890&pid=100&v=2&ts=1234567890&pn=test_core_bidder%3A234&advertiser_id=a.com&sURL=com.someapp.com&pfi=7&af=video&iid=abc~%21%40%23%24%25%5E%26%26%2A%28%29_%2B%7B%7D%7C%3A%22%3C%3E%3F%5B%5D%5C%3B%27%2C.%2F&pseq=[PODSEQUENCE]&adcnt=[ADCOUNT]&cb=[CACHEBUSTING]&au=%2Ftestadunit%2F1&bidid=test_bid_id&origbidid=test_bid_id&bc=test_bidder%3A234"}, + wantVastXml: ``, + wantErr: nil, + metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, }, }, + // { + // name: "vast_and_adm_empty - This should never be the case as modifyBidVAST always updates AdM with tempate vast", + // args: args{ + // externalURL: "http://company.tracker.com?eventId=[EVENT_ID]&appbundle=[DOMAIN]", + // vastXML: "", + // bid: &openrtb2.Bid{ // Adm contains to TrackingEvents tag + // AdM: "", + // NURL: "nurl_contents", + // }, + // req: &openrtb2.BidRequest{App: &openrtb2.App{Bundle: "abc"}}, + // }, + // want : want{ + // wantVastXml: "", + // wantErr: errors.New("error parsing VAST XML. 'EOF'"), + // metrics: &openrtb_ext.FastXMLMetrics{IsRespMismatch: false}, + // }, + // }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - - if nil == tc.args.bid { - tc.args.bid = &openrtb2.Bid{} + injectedVast, metrics, err := InjectVideoEventTrackers(tc.args.req, tc.args.bid, tc.args.vastXML, tc.args.externalURL, tc.args.genbidID, "test_bidder", "test_core_bidder", int64(0), true) + assert.Equal(t, tc.want.wantErr, err) + assert.Equal(t, tc.want.wantVastXml, string(injectedVast)) + if tc.want.metrics != nil { + assert.NotNil(t, metrics) + assert.Equal(t, tc.want.metrics.IsRespMismatch, metrics.IsRespMismatch) } + }) + } +} - impMap := map[string]*openrtb2.Imp{} - - for _, imp := range tc.args.req.Imp { - impMap[imp.ID] = &imp - } - - eventURLMap := GetVideoEventTracking(tc.args.trackerURL, tc.args.bid, tc.args.gen_bidid, tc.args.requestingBidder, tc.args.bidderCoreName, tc.args.accountId, tc.args.timestamp, tc.args.req, tc.args.doc, impMap) - - for event, eurl := range tc.want.trackerURLMap { - - u, _ := url.Parse(eurl) - expectedValues, _ := url.ParseQuery(u.RawQuery) - u, _ = url.Parse(eventURLMap[event]) - actualValues, _ := url.ParseQuery(u.RawQuery) - for k, ev := range expectedValues { - av := actualValues[k] - for i := 0; i < len(ev); i++ { - assert.Equal(t, ev[i], av[i], fmt.Sprintf("Expected '%v' for '%v'. but found %v", ev[i], k, av[i])) - } - } - - // error out if extra query params - if len(expectedValues) != len(actualValues) { - assert.Equal(t, expectedValues, actualValues, fmt.Sprintf("Expected '%v' query params but found '%v'", len(expectedValues), len(actualValues))) - break +func quoteUnescape[T []byte | string](s T) string { + buf := bytes.Buffer{} + for i := 0; i < len(s); i++ { + ch := s[i] + if ch == '\\' { + if i+1 < len(s) { + nextCh := s[i+1] + if nextCh == '\\' || nextCh == '"' || nextCh == '\'' { + i++ + ch = nextCh } } - - // check if new quartile pixels are covered inside test - assert.Equal(t, tc.want.trackerURLMap, eventURLMap) - }) + } + buf.WriteByte(ch) } + return buf.String() } -func TestReplaceMacro(t *testing.T) { - type args struct { - trackerURL string - macro string - value string - } - type want struct { - trackerURL string - } - tests := []struct { - name string - args args - want want - }{ - {name: "empty_tracker_url", args: args{trackerURL: "", macro: "[TEST]", value: "testme"}, want: want{trackerURL: ""}}, - {name: "tracker_url_with_macro", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "[TEST]", value: "testme"}, want: want{trackerURL: "http://something.com?test=testme"}}, - {name: "tracker_url_with_invalid_macro", args: args{trackerURL: "http://something.com?test=TEST]", macro: "[TEST]", value: "testme"}, want: want{trackerURL: "http://something.com?test=TEST]"}}, - {name: "tracker_url_with_repeating_macro", args: args{trackerURL: "http://something.com?test=[TEST]&test1=[TEST]", macro: "[TEST]", value: "testme"}, want: want{trackerURL: "http://something.com?test=testme&test1=testme"}}, - {name: "empty_macro", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "", value: "testme"}, want: want{trackerURL: "http://something.com?test=[TEST]"}}, - {name: "macro_without_[", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "TEST]", value: "testme"}, want: want{trackerURL: "http://something.com?test=[TEST]"}}, - {name: "macro_without_]", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "[TEST", value: "testme"}, want: want{trackerURL: "http://something.com?test=[TEST]"}}, - {name: "empty_value", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "[TEST]", value: ""}, want: want{trackerURL: "http://something.com?test="}}, - {name: "nested_macro_value", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "[TEST]", value: "[TEST][TEST]"}, want: want{trackerURL: "http://something.com?test=%5BTEST%5D%5BTEST%5D"}}, - {name: "url_as_macro_value", args: args{trackerURL: "http://something.com?test=[TEST]", macro: "[TEST]", value: "http://iamurl.com"}, want: want{trackerURL: "http://something.com?test=http%3A%2F%2Fiamurl.com"}}, - {name: "macro_with_spaces", args: args{trackerURL: "http://something.com?test=[TEST]", macro: " [TEST] ", value: "http://iamurl.com"}, want: want{trackerURL: "http://something.com?test=http%3A%2F%2Fiamurl.com"}}, - } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - trackerURL := replaceMacro(tc.args.trackerURL, tc.args.macro, tc.args.value) - assert.Equal(t, tc.want.trackerURL, trackerURL) - }) - } +func TestCompareXMLParsers(t *testing.T) { + //fileName := `./test/base64_vast.txt` + fileName := `./test/raw_vast.txt` -} -func TestExtractDomain(t *testing.T) { - testCases := []struct { - description string - url string - expectedDomain string - expectedErr error - }{ - {description: "a.com", url: "a.com", expectedDomain: "a.com", expectedErr: nil}, - {description: "a.com/123", url: "a.com/123", expectedDomain: "a.com", expectedErr: nil}, - {description: "http://a.com/123", url: "http://a.com/123", expectedDomain: "a.com", expectedErr: nil}, - {description: "https://a.com/123", url: "https://a.com/123", expectedDomain: "a.com", expectedErr: nil}, - {description: "c.b.a.com", url: "c.b.a.com", expectedDomain: "c.b.a.com", expectedErr: nil}, - {description: "url_encoded_http://c.b.a.com", url: "http%3A%2F%2Fc.b.a.com", expectedDomain: "c.b.a.com", expectedErr: nil}, - {description: "url_encoded_with_www_http://c.b.a.com", url: "http%3A%2F%2Fwww.c.b.a.com", expectedDomain: "c.b.a.com", expectedErr: nil}, + base64Decode := strings.Contains(fileName, "base64") + + file, err := os.Open(fileName) + if !assert.Nil(t, err) { + return } - for _, test := range testCases { - t.Run(test.description, func(t *testing.T) { - domain, err := extractDomain(test.url) - assert.Equal(t, test.expectedDomain, domain) - assert.Equal(t, test.expectedErr, err) + + defer file.Close() + var mismatched []int + var debugLines map[int]bool + line := 0 + scanner := bufio.NewScanner(file) + scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024) + //debugLines = map[int]bool{29: true, 30: true, 33: true, 50: true, 93: true} + + for scanner.Scan() { + line++ + vast := scanner.Text() + if len(debugLines) > 0 { + if debugLines[line] == false { + continue + } + } + if base64Decode { + data, err := base64.StdEncoding.DecodeString(vast) + if !assert.Nil(t, err) { + continue + } + vast = quoteUnescape(data) + } + t.Run(fmt.Sprintf("vast_%d", line), func(t *testing.T) { + etreeXML, _ := injectVideoEventsETree(vast, eventURLMap, false, adcom1.LinearityLinear) + fastXML, _ := injectVideoEventsFastXML(vast, eventURLMap, false, adcom1.LinearityLinear) + if vast != fastXML { + //replace only if trackers are injected + fastXML = strings.ReplaceAll(fastXML, " >", ">") + } + + if etreeXML != fastXML { + assert.Equal(t, etreeXML, fastXML) + mismatched = append(mismatched, line) + } }) } + fmt.Printf("\n total:[%v] mismatched:[%v] lines:[%v]", line, len(mismatched), mismatched) + assert.Equal(t, 0, len(mismatched)) + assert.Nil(t, scanner.Err()) } diff --git a/exchange/events.go b/exchange/events.go index 2ec63ccfefb..4d9f2bf4a8c 100644 --- a/exchange/events.go +++ b/exchange/events.go @@ -16,10 +16,10 @@ import ( // eventTracking has configuration fields needed for adding event tracking to an auction response type eventTracking struct { + OpenWrapEventTracking accountID string enabledForAccount bool enabledForRequest bool - enabledVideoEvents bool //TODO: OPENWRAP Video Events Flag auctionTimestampMs int64 integrationType string bidderInfos config.BidderInfos @@ -27,16 +27,16 @@ type eventTracking struct { } // getEventTracking creates an eventTracking object from the different configuration sources -func getEventTracking(requestExtPrebid *openrtb_ext.ExtRequestPrebid, ts time.Time, account *config.Account, bidderInfos config.BidderInfos, externalURL string) *eventTracking { +func getEventTracking(requestExtPrebid *openrtb_ext.ExtRequestPrebid, ts time.Time, account *config.Account, bidderInfos config.BidderInfos, externalURL string, owEventTracking OpenWrapEventTracking) *eventTracking { return &eventTracking{ - accountID: account.ID, - enabledForAccount: account.Events.Enabled, - enabledForRequest: requestExtPrebid != nil && requestExtPrebid.Events != nil, - enabledVideoEvents: requestExtPrebid == nil || !requestExtPrebid.ExtOWRequestPrebid.TrackerDisabled, - auctionTimestampMs: ts.UnixNano() / 1e+6, - integrationType: getIntegrationType(requestExtPrebid), - bidderInfos: bidderInfos, - externalURL: externalURL, + accountID: account.ID, + enabledForAccount: account.Events.Enabled, + enabledForRequest: requestExtPrebid != nil && requestExtPrebid.Events != nil, + auctionTimestampMs: ts.UnixNano() / 1e+6, + integrationType: getIntegrationType(requestExtPrebid), + bidderInfos: bidderInfos, + externalURL: externalURL, + OpenWrapEventTracking: owEventTracking, } } @@ -81,12 +81,7 @@ func (ev *eventTracking) modifyBidVAST(pbsBid *entities.PbsOrtbBid, bidderName o } } - if ev.enabledVideoEvents { - // always inject event trackers without checkign isModifyingVASTXMLAllowed - if newVastXML, injected, _ := events.InjectVideoEventTrackers(trackerURL, vastXML, bid, bidID, bidderName.String(), bidderCoreName.String(), ev.accountID, ev.auctionTimestampMs, req); injected { - bid.AdM = string(newVastXML) - } - } + ev.injectVideoEvents(req, bid, vastXML, trackerURL, bidID, bidderName.String(), bidderCoreName.String()) } // modifyBidJSON injects "wurl" (win) event url if needed, otherwise returns original json diff --git a/exchange/events_ow.go b/exchange/events_ow.go new file mode 100644 index 00000000000..3f6dfb4ac8d --- /dev/null +++ b/exchange/events_ow.go @@ -0,0 +1,37 @@ +package exchange + +import ( + "github.com/golang/glog" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/endpoints/events" + "github.com/prebid/prebid-server/v2/metrics" +) + +type OpenWrapEventTracking struct { + enabledVideoEvents bool + enableFastXML bool + me metrics.MetricsEngine +} + +func (ev *eventTracking) injectVideoEvents( + bidRequest *openrtb2.BidRequest, + bid *openrtb2.Bid, + vastXML, trackerURL, bidID, requestingBidder, bidderCoreName string) { + + if !ev.enabledVideoEvents { + return + } + + // always inject event trackers without checkign isModifyingVASTXMLAllowed + newVastXML, metrics, err := events.InjectVideoEventTrackers(bidRequest, bid, vastXML, trackerURL, bidID, requestingBidder, bidderCoreName, ev.auctionTimestampMs, ev.enableFastXML) + if err == nil { + bid.AdM = newVastXML + } + + if metrics != nil && ev.me != nil { + recordFastXMLMetrics(ev.me, "vast_events_injection", requestingBidder, metrics) + if metrics.IsRespMismatch { + glog.V(2).Infof("\n[XML_PARSER_TEST] method:[vcr] creative:[%s]", vastXML) + } + } +} diff --git a/exchange/events_ow_test.go b/exchange/events_ow_test.go new file mode 100644 index 00000000000..f7bfcd4e2f3 --- /dev/null +++ b/exchange/events_ow_test.go @@ -0,0 +1,74 @@ +package exchange + +import ( + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/exchange/entities" + "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func TestModifyBidVAST(t *testing.T) { + type args struct { + enabledVideoEvents bool + bidReq *openrtb2.BidRequest + bid *openrtb2.Bid + } + tests := []struct { + name string + args args + wantAdM string + }{ + { + name: "empty_adm", // expect adm contain vast tag with tracking events and VASTAdTagURI nurl contents + args: args{ + enabledVideoEvents: true, + bidReq: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + }, + bid: &openrtb2.Bid{ + AdM: "", + NURL: "nurl_contents", + ImpID: "123", + }, + }, + wantAdM: ``, + }, + { + name: "adm_containing_url", // expect adm contain vast tag with tracking events and VASTAdTagURI adm url (previous value) contents + args: args{ + enabledVideoEvents: true, + bidReq: &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, + }, + bid: &openrtb2.Bid{ + AdM: "http://vast_tag_inline.xml", + NURL: "nurl_contents", + ImpID: "123", + }, + }, + wantAdM: ``, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ev := eventTracking{ + bidderInfos: config.BidderInfos{ + "somebidder": config.BidderInfo{ + ModifyingVastXmlAllowed: false, + }, + }, + OpenWrapEventTracking: OpenWrapEventTracking{ + enabledVideoEvents: tc.args.enabledVideoEvents, + }, + } + ev.modifyBidVAST(&entities.PbsOrtbBid{ + Bid: tc.args.bid, + BidType: openrtb_ext.BidTypeVideo, + }, "somebidder", "coreBidder", tc.args.bidReq, "http://company.tracker.com?e=[EVENT_ID]") + assert.Equal(t, tc.wantAdM, tc.args.bid.AdM) + }) + } +} diff --git a/exchange/events_test.go b/exchange/events_test.go index 0dd3c8a9920..a4ed587cd67 100644 --- a/exchange/events_test.go +++ b/exchange/events_test.go @@ -1,11 +1,9 @@ package exchange import ( - "strings" "testing" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v2/config" "github.com/prebid/prebid-server/v2/exchange/entities" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" @@ -194,112 +192,3 @@ func Test_isEventAllowed(t *testing.T) { }) } } - -func TestModifyBidVAST(t *testing.T) { - type args struct { - enabledVideoEvents bool - bidReq *openrtb2.BidRequest - bid *openrtb2.Bid - } - type want struct { - tags []string - } - tests := []struct { - name string - args args - want want - }{ - { - name: "empty_adm", // expect adm contain vast tag with tracking events and VASTAdTagURI nurl contents - args: args{ - enabledVideoEvents: true, - bidReq: &openrtb2.BidRequest{ - Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, - }, - bid: &openrtb2.Bid{ - AdM: "", - NURL: "nurl_contents", - ImpID: "123", - }, - }, - want: want{ - tags: []string{ - // ``, - // ``, - // ``, - // ``, - // "", - // "", - // "", - ``, - ``, - ``, - ``, - "", - "", - "", - }, - }, - }, - { - name: "adm_containing_url", // expect adm contain vast tag with tracking events and VASTAdTagURI adm url (previous value) contents - args: args{ - enabledVideoEvents: true, - bidReq: &openrtb2.BidRequest{ - Imp: []openrtb2.Imp{{ID: "123", Video: &openrtb2.Video{}}}, - }, - bid: &openrtb2.Bid{ - AdM: "http://vast_tag_inline.xml", - NURL: "nurl_contents", - ImpID: "123", - }, - }, - want: want{ - tags: []string{ - // ``, - // ``, - // ``, - // ``, - // "", - // "", - // "", - ``, - ``, - ``, - ``, - "", - "", - "", - }, - }, - }, - } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - ev := eventTracking{ - bidderInfos: config.BidderInfos{ - "somebidder": config.BidderInfo{ - ModifyingVastXmlAllowed: false, - }, - }, - enabledVideoEvents: tc.args.enabledVideoEvents, - } - ev.modifyBidVAST(&entities.PbsOrtbBid{ - Bid: tc.args.bid, - BidType: openrtb_ext.BidTypeVideo, - }, "somebidder", "coreBidder", tc.args.bidReq, "http://company.tracker.com?e=[EVENT_ID]") - validator(t, tc.args.bid, tc.want.tags) - }) - } -} - -func validator(t *testing.T, b *openrtb2.Bid, expectedTags []string) { - adm := b.AdM - assert.NotNil(t, adm) - assert.NotEmpty(t, adm) - // check tags are present - - for _, tag := range expectedTags { - assert.True(t, strings.Contains(adm, tag), "expected '"+tag+"' tag in Adm") - } -} diff --git a/exchange/exchange.go b/exchange/exchange.go index 166a5675547..58eb99704d4 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -493,7 +493,12 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog } } - evTracking := getEventTracking(requestExtPrebid, r.StartTime, &r.Account, e.bidderInfo, e.externalURL) + evTracking := getEventTracking(requestExtPrebid, r.StartTime, &r.Account, e.bidderInfo, e.externalURL, + OpenWrapEventTracking{ + enabledVideoEvents: requestExtPrebid == nil || !requestExtPrebid.ExtOWRequestPrebid.TrackerDisabled, + enableFastXML: e.server.EnableFastXML, + me: e.me, + }) adapterBids = evTracking.modifyBidsForEvents(adapterBids, r.BidRequestWrapper.BidRequest, e.trakerURL) r.HookExecutor.ExecuteAllProcessedBidResponsesStage(adapterBids) diff --git a/exchange/exchange_ow.go b/exchange/exchange_ow.go index b02899742da..59a46e1a73f 100644 --- a/exchange/exchange_ow.go +++ b/exchange/exchange_ow.go @@ -205,7 +205,7 @@ func recordOpenWrapBidResponseMetrics(bidder *bidderAdapter, bidResponse *adapte recordFastXMLMetrics(bidder.me, "vastbidder", string(bidder.BidderName), bidResponse.FastXMLMetrics) if bidResponse.FastXMLMetrics.IsRespMismatch { resp, _ := jsonutil.Marshal(bidResponse) - glog.V(2).Infof("\n[VAST_BIDDER] Response Mismatch for Creative : %s", string(resp)) + glog.V(2).Infof("\n[XML_PARSER_TEST] method:[vast_bidder] response:[%s]", resp) } } diff --git a/go.mod b/go.mod index b9f7f938308..ca4605b06ca 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( git.pubmatic.com/PubMatic/go-common v0.0.0-20240313090142-97ff3d63b7c3 git.pubmatic.com/PubMatic/go-netacuity-client v0.0.0-20240104092757-5d6f15e25fe3 git.pubmatic.com/vastunwrap v0.0.0-00010101000000-000000000000 - github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240621094509-2f843d282179 + github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2 github.com/diegoholiveira/jsonlogic/v3 v3.5.3 github.com/go-sql-driver/mysql v1.7.1 github.com/golang/mock v1.6.0 @@ -88,9 +88,9 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect + github.com/yudai/pp v2.0.1+incompatible // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/sys v0.18.0 // indirect - github.com/yudai/pp v2.0.1+incompatible // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -100,6 +100,6 @@ replace github.com/prebid/prebid-server/v2 => ./ replace github.com/prebid/openrtb/v20 => github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef -replace github.com/beevik/etree v1.0.2 => github.com/PubMatic-OpenWrap/etree v1.0.2-0.20210129100623-8f30cfecf9f4 +replace github.com/beevik/etree v1.0.2 => github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240721064252-bb63229a1baa replace github.com/beevik/etree/110 => github.com/beevik/etree v1.1.0 diff --git a/go.sum b/go.sum index 13321359a53..cea4b242fb7 100644 --- a/go.sum +++ b/go.sum @@ -315,10 +315,12 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PubMatic-OpenWrap/etree v1.0.2-0.20210129100623-8f30cfecf9f4 h1:EhiijwjoKTx7FVP8p2wwC/z4n5l4c8l2CGmsrFv2uhI= -github.com/PubMatic-OpenWrap/etree v1.0.2-0.20210129100623-8f30cfecf9f4/go.mod h1:5Y8qgcuDoy3XXG907UXkGnVTwihF16rXyJa4zRT7hOE= -github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240621094509-2f843d282179 h1:XhtshM/kxpjzShEebApfcvPv1ue3LynvvKNCW2SMONA= -github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240621094509-2f843d282179/go.mod h1:TGGzSA5ziWpfLsKvqOzgdPGEZ7SJIQjHbcJw6lWoyHU= +github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240721064252-bb63229a1baa h1:3tRjI/7/JkTX2tnIvjEbOUTgJJ4rq4oz2hWSU8jvjH8= +github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240721064252-bb63229a1baa/go.mod h1:5Y8qgcuDoy3XXG907UXkGnVTwihF16rXyJa4zRT7hOE= +github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240823084925-e25a796a41bd h1:5IlcLRGtf1EPaVF+ySv7QidGzcwE3xKALhQxMLXOKus= +github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240823084925-e25a796a41bd/go.mod h1:TGGzSA5ziWpfLsKvqOzgdPGEZ7SJIQjHbcJw6lWoyHU= +github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2 h1:4zaGImZVnKCJudxKfsVNJAqGhCPxbjApAo0QvEThwpw= +github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2/go.mod h1:TGGzSA5ziWpfLsKvqOzgdPGEZ7SJIQjHbcJw6lWoyHU= github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef h1:CXsyYtEgZz/0++fiug6QZXrRYG6BBrl9IGveCxsnhiE= github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef/go.mod h1:hLBrA/APkSrxs5MaW639l+y/EAHivDfRagO2TX/wbSc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -824,9 +826,9 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/rs/vast v0.0.0-20180618195556-06597a11a4c3 h1:PSgAIBGyQP7KW2+EElPsa3qmaya7kCxLSI/GBR176MQ= github.com/rs/vast v0.0.0-20180618195556-06597a11a4c3/go.mod h1:gq4gkWd7KdigGXkRdN5GEgBQYAWDTmD4/U65MdCgLxQ= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= diff --git a/modules/pubmatic/openwrap/tracker/video_test.go b/modules/pubmatic/openwrap/tracker/video_test.go index 7a4599335d5..3995b480092 100644 --- a/modules/pubmatic/openwrap/tracker/video_test.go +++ b/modules/pubmatic/openwrap/tracker/video_test.go @@ -289,7 +289,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { }, }, }, - wantAdm: ``, + wantAdm: ` `, wantErr: false, }, { @@ -449,7 +449,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { }, }, wantBurl: "Tracker URL&owsspburl=https://burl.com", - wantAdm: ``, + wantAdm: ` `, wantErr: false, }, } From 5e667cfa2c00713d419787a8d7fd7be956107ad9 Mon Sep 17 00:00:00 2001 From: pm-avinash-kapre <112699665+AvinashKapre@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:14:00 +0530 Subject: [PATCH 07/24] UOE-10993: Support for apppLovinMax endpoint- Read and forwrad DSA objetc from the signal regs.ext (#893) --- modules/pubmatic/openwrap/applovinmax.go | 2 +- modules/pubmatic/openwrap/applovinmax_test.go | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/pubmatic/openwrap/applovinmax.go b/modules/pubmatic/openwrap/applovinmax.go index c8630f32ac8..185d45e1693 100644 --- a/modules/pubmatic/openwrap/applovinmax.go +++ b/modules/pubmatic/openwrap/applovinmax.go @@ -144,7 +144,7 @@ func updateRegs(signalRegs *openrtb2.Regs, maxRequest *openrtb2.BidRequest) { if signalRegs.COPPA != 0 { maxRequest.Regs.COPPA = signalRegs.COPPA } - maxRequest.Regs.Ext = setIfKeysExists(signalRegs.Ext, maxRequest.Regs.Ext, "gdpr", "gpp", "gpp_sid", "us_privacy") + maxRequest.Regs.Ext = setIfKeysExists(signalRegs.Ext, maxRequest.Regs.Ext, "gdpr", "gpp", "gpp_sid", "us_privacy", "dsa") } func updateSource(signalSource *openrtb2.Source, maxRequest *openrtb2.BidRequest) { diff --git a/modules/pubmatic/openwrap/applovinmax_test.go b/modules/pubmatic/openwrap/applovinmax_test.go index 229ddcfcbdf..c3e77bc204f 100644 --- a/modules/pubmatic/openwrap/applovinmax_test.go +++ b/modules/pubmatic/openwrap/applovinmax_test.go @@ -289,6 +289,22 @@ func TestUpdateRegs(t *testing.T) { }, want: &openrtb2.Regs{Ext: json.RawMessage(`{"gpp":"sdfewe3cer","gdpr":1,"gpp_sid":[6],"us_privacy":"uspConsentString"}`)}, }, + { + name: "signalRegsExt has dsa", + args: args{ + signalRegs: &openrtb2.Regs{Ext: json.RawMessage(`{"dsa":{"dsarequired":3,"pubrender":2,"datatopub":1,"transparency":[{"domain":"params.com","params":[1,2]},{"domain":"dsaicon2.com","params":[2,3]}]}}`)}, + maxRequest: &openrtb2.BidRequest{}, + }, + want: &openrtb2.Regs{Ext: json.RawMessage(`{"dsa":{"dsarequired":3,"pubrender":2,"datatopub":1,"transparency":[{"domain":"params.com","params":[1,2]},{"domain":"dsaicon2.com","params":[2,3]}]}}`)}, + }, + { + name: "signalRegsExt has gdpr, gpp, gp_sid, us_privacy, dsa and maxRegsExt has gpp", + args: args{ + signalRegs: &openrtb2.Regs{Ext: json.RawMessage(`{"gdpr":1,"gpp":"sdfewe3cer","gpp_sid":[6],"us_privacy":"uspConsentString","dsa":{"dsarequired":3,"pubrender":2,"datatopub":1,"transparency":[{"domain":"params.com","params":[1,2]},{"domain":"dsaicon2.com","params":[2,3]}]}`)}, + maxRequest: &openrtb2.BidRequest{Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"gpp":"gpp_string"}`)}}, + }, + want: &openrtb2.Regs{Ext: json.RawMessage(`{"gpp":"sdfewe3cer","gdpr":1,"gpp_sid":[6],"us_privacy":"uspConsentString","dsa":{"dsarequired":3,"pubrender":2,"datatopub":1,"transparency":[{"domain":"params.com","params":[1,2]},{"domain":"dsaicon2.com","params":[2,3]}]}}`)}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From fbd2a2cb1d3aaae25e6468df8326200a79c653e2 Mon Sep 17 00:00:00 2001 From: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:09:19 +0530 Subject: [PATCH 08/24] OTT-1824-P1: enabling fastxml for vcr (#894) --- exchange/exchange.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exchange/exchange.go b/exchange/exchange.go index 58eb99704d4..9d66d19acc1 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -176,7 +176,7 @@ func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid bidIDGenerator: &bidIDGenerator{cfg.GenerateBidID}, hostSChainNode: cfg.HostSChainNode, adsCertSigner: adsCertSigner, - server: config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter}, + server: config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter, EnableFastXML: cfg.EnableFastXML}, bidValidationEnforcement: cfg.Validations, requestSplitter: requestSplitter, macroReplacer: macroReplacer, From b5d950c23fcc3152bf99f8d88997d759dba69577 Mon Sep 17 00:00:00 2001 From: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:56:45 +0530 Subject: [PATCH 09/24] OTT-1824-P2 removing bidder key and updating logs for fastxml (#896) --- endpoints/events/test/vast.txt | 66 ++++++++++++++++++++++++ endpoints/events/vtrack_ow.go | 14 ++++- endpoints/events/vtrack_ow_test.go | 23 +++++++-- exchange/events_ow.go | 6 +-- exchange/exchange_ow.go | 10 ++-- exchange/exchange_ow_test.go | 17 +++--- metrics/config/metrics_ow.go | 24 ++++----- metrics/go_metrics_ow.go | 4 +- metrics/metrics_mock_ow.go | 8 +-- metrics/metrics_ow.go | 4 +- metrics/prometheus/prometheus_ow.go | 20 ++++--- metrics/prometheus/prometheus_ow_test.go | 13 ++--- 12 files changed, 146 insertions(+), 63 deletions(-) create mode 100644 endpoints/events/test/vast.txt diff --git a/endpoints/events/test/vast.txt b/endpoints/events/test/vast.txt new file mode 100644 index 00000000000..24cc528359a --- /dev/null +++ b/endpoints/events/test/vast.txt @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + +00:00:26 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/endpoints/events/vtrack_ow.go b/endpoints/events/vtrack_ow.go index f30e198d530..0906b8aa5d9 100644 --- a/endpoints/events/vtrack_ow.go +++ b/endpoints/events/vtrack_ow.go @@ -2,12 +2,15 @@ package events import ( "bytes" + "encoding/base64" "errors" + "math/rand" "strings" "time" "github.com/PubMatic-OpenWrap/fastxml" "github.com/beevik/etree" + "github.com/golang/glog" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/openrtb_ext" @@ -60,10 +63,19 @@ func InjectVideoEventTrackers( fastXMLResponse = strings.ReplaceAll(fastXMLResponse, " >", ">") } + isResponseMismatch := (response != fastXMLResponse) + + if isResponseMismatch { + random := rand.Int() + glog.V(2).Infof("[XML_PARSER_TEST] method:[vcr] rand:[%v] creative:[%s]", random, base64.StdEncoding.EncodeToString([]byte(vastXML))) + //glog.V(2).Infof("[XML_PARSER_TEST] method:[vcr] rand:[%v] etree:[%s]", random, base64.StdEncoding.EncodeToString([]byte(response))) + //glog.V(2).Infof("[XML_PARSER_TEST] method:[vcr] rand:[%v] fastxml:[%s]", random, base64.StdEncoding.EncodeToString([]byte(fastXMLResponse))) + } + metrics = &openrtb_ext.FastXMLMetrics{ XMLParserTime: fastXMLParserTime, EtreeParserTime: etreeParserTime, - IsRespMismatch: (response != fastXMLResponse), + IsRespMismatch: isResponseMismatch, } } diff --git a/endpoints/events/vtrack_ow_test.go b/endpoints/events/vtrack_ow_test.go index 4b7baaf39cd..ebf81d9f430 100644 --- a/endpoints/events/vtrack_ow_test.go +++ b/endpoints/events/vtrack_ow_test.go @@ -490,13 +490,30 @@ func TestCompareXMLParsers(t *testing.T) { fastXML = strings.ReplaceAll(fastXML, " >", ">") } - if etreeXML != fastXML { - assert.Equal(t, etreeXML, fastXML) + if !assert.Equal(t, etreeXML, fastXML) { mismatched = append(mismatched, line) } }) } - fmt.Printf("\n total:[%v] mismatched:[%v] lines:[%v]", line, len(mismatched), mismatched) + t.Logf("\n total:[%v] mismatched:[%v] lines:[%v]", line, len(mismatched), mismatched) assert.Equal(t, 0, len(mismatched)) assert.Nil(t, scanner.Err()) } + +func TestCompare(t *testing.T) { + vastBytes, err := os.ReadFile(`./test/vast.txt`) + assert.NoError(t, err) + + vast := string(vastBytes) + etreeXML, err := injectVideoEventsETree(vast, eventURLMap, false, adcom1.LinearityLinear) + assert.NoError(t, err) + + fastXML, err := injectVideoEventsFastXML(vast, eventURLMap, false, adcom1.LinearityLinear) + assert.NoError(t, err) + + if vast != fastXML { + //replace only if trackers are injected + fastXML = strings.ReplaceAll(fastXML, " >", ">") + } + assert.Equal(t, etreeXML, fastXML) +} diff --git a/exchange/events_ow.go b/exchange/events_ow.go index 3f6dfb4ac8d..f0a881a61d4 100644 --- a/exchange/events_ow.go +++ b/exchange/events_ow.go @@ -1,7 +1,6 @@ package exchange import ( - "github.com/golang/glog" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/endpoints/events" "github.com/prebid/prebid-server/v2/metrics" @@ -29,9 +28,6 @@ func (ev *eventTracking) injectVideoEvents( } if metrics != nil && ev.me != nil { - recordFastXMLMetrics(ev.me, "vast_events_injection", requestingBidder, metrics) - if metrics.IsRespMismatch { - glog.V(2).Infof("\n[XML_PARSER_TEST] method:[vcr] creative:[%s]", vastXML) - } + recordFastXMLMetrics(ev.me, "vcr", metrics) } } diff --git a/exchange/exchange_ow.go b/exchange/exchange_ow.go index 59a46e1a73f..38ddd84c57b 100644 --- a/exchange/exchange_ow.go +++ b/exchange/exchange_ow.go @@ -202,7 +202,7 @@ func recordOpenWrapBidResponseMetrics(bidder *bidderAdapter, bidResponse *adapte } if bidResponse.FastXMLMetrics != nil { - recordFastXMLMetrics(bidder.me, "vastbidder", string(bidder.BidderName), bidResponse.FastXMLMetrics) + recordFastXMLMetrics(bidder.me, "vastbidder", bidResponse.FastXMLMetrics) if bidResponse.FastXMLMetrics.IsRespMismatch { resp, _ := jsonutil.Marshal(bidResponse) glog.V(2).Infof("\n[XML_PARSER_TEST] method:[vast_bidder] response:[%s]", resp) @@ -212,10 +212,10 @@ func recordOpenWrapBidResponseMetrics(bidder *bidderAdapter, bidResponse *adapte recordVASTTagType(bidder.me, bidResponse, bidder.BidderName) } -func recordFastXMLMetrics(metricsEngine metrics.MetricsEngine, method string, bidder string, vastBidderInfo *openrtb_ext.FastXMLMetrics) { - metricsEngine.RecordXMLParserResponseTime(metrics.XMLParserLabelFastXML, method, bidder, vastBidderInfo.XMLParserTime) - metricsEngine.RecordXMLParserResponseTime(metrics.XMLParserLabelETree, method, bidder, vastBidderInfo.EtreeParserTime) - metricsEngine.RecordXMLParserResponseMismatch(method, bidder, vastBidderInfo.IsRespMismatch) +func recordFastXMLMetrics(metricsEngine metrics.MetricsEngine, method string, vastBidderInfo *openrtb_ext.FastXMLMetrics) { + metricsEngine.RecordXMLParserResponseTime(metrics.XMLParserLabelFastXML, method, vastBidderInfo.XMLParserTime) + metricsEngine.RecordXMLParserResponseTime(metrics.XMLParserLabelETree, method, vastBidderInfo.EtreeParserTime) + metricsEngine.RecordXMLParserResponseMismatch(method, vastBidderInfo.IsRespMismatch) } func recordVASTTagType(metricsEngine metrics.MetricsEngine, adapterBids *adapters.BidderResponse, bidder openrtb_ext.BidderName) { diff --git a/exchange/exchange_ow_test.go b/exchange/exchange_ow_test.go index 661cf4b6b2e..78ebf3dff1f 100644 --- a/exchange/exchange_ow_test.go +++ b/exchange/exchange_ow_test.go @@ -1823,7 +1823,6 @@ func TestRecordFastXMLMetrics(t *testing.T) { testMethodName := "test" type args struct { - bidder string vastBidderInfo *openrtb_ext.FastXMLMetrics getMetricsEngine func() *metrics.MetricsEngineMock } @@ -1835,7 +1834,6 @@ func TestRecordFastXMLMetrics(t *testing.T) { { name: "Record_Fast_XML_Metrics_Respnse_matched", args: args{ - bidder: "pubmatic", vastBidderInfo: &openrtb_ext.FastXMLMetrics{ XMLParserTime: time.Millisecond * 10, EtreeParserTime: time.Millisecond * 20, @@ -1843,9 +1841,9 @@ func TestRecordFastXMLMetrics(t *testing.T) { }, getMetricsEngine: func() *metrics.MetricsEngineMock { metricEngine := &metrics.MetricsEngineMock{} - metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelFastXML, testMethodName, "pubmatic", time.Millisecond*10).Return() - metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelETree, testMethodName, "pubmatic", time.Millisecond*20).Return() - metricEngine.Mock.On("RecordXMLParserResponseMismatch", testMethodName, "pubmatic", false).Return() + metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelFastXML, testMethodName, time.Millisecond*10).Return() + metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelETree, testMethodName, time.Millisecond*20).Return() + metricEngine.Mock.On("RecordXMLParserResponseMismatch", testMethodName, false).Return() return metricEngine }, }, @@ -1853,7 +1851,6 @@ func TestRecordFastXMLMetrics(t *testing.T) { { name: "Record_Fast_XML_Metrics_Respnse_mismatched", args: args{ - bidder: "pubmatic", vastBidderInfo: &openrtb_ext.FastXMLMetrics{ XMLParserTime: time.Millisecond * 15, EtreeParserTime: time.Millisecond * 25, @@ -1861,9 +1858,9 @@ func TestRecordFastXMLMetrics(t *testing.T) { }, getMetricsEngine: func() *metrics.MetricsEngineMock { metricEngine := &metrics.MetricsEngineMock{} - metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelFastXML, testMethodName, "pubmatic", time.Millisecond*15).Return() - metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelETree, testMethodName, "pubmatic", time.Millisecond*25).Return() - metricEngine.Mock.On("RecordXMLParserResponseMismatch", testMethodName, "pubmatic", true).Return() + metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelFastXML, testMethodName, time.Millisecond*15).Return() + metricEngine.Mock.On("RecordXMLParserResponseTime", metrics.XMLParserLabelETree, testMethodName, time.Millisecond*25).Return() + metricEngine.Mock.On("RecordXMLParserResponseMismatch", testMethodName, true).Return() return metricEngine }, }, @@ -1873,7 +1870,7 @@ func TestRecordFastXMLMetrics(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockMetricEngine := tt.args.getMetricsEngine() - recordFastXMLMetrics(mockMetricEngine, testMethodName, tt.args.bidder, tt.args.vastBidderInfo) + recordFastXMLMetrics(mockMetricEngine, testMethodName, tt.args.vastBidderInfo) mockMetricEngine.AssertExpectations(t) }) } diff --git a/metrics/config/metrics_ow.go b/metrics/config/metrics_ow.go index 9e793527d2c..149e920f5a7 100644 --- a/metrics/config/metrics_ow.go +++ b/metrics/config/metrics_ow.go @@ -26,15 +26,15 @@ func NewMetricsRegistry() MetricsRegistry { } // RecordXMLParserResponseTime records execution time for multiple parsers -func (me *MultiMetricsEngine) RecordXMLParserResponseTime(parser string, method string, bidder string, respTime time.Duration) { +func (me *MultiMetricsEngine) RecordXMLParserResponseTime(parser string, method string, respTime time.Duration) { for _, thisME := range *me { - thisME.RecordXMLParserResponseTime(parser, method, bidder, respTime) + thisME.RecordXMLParserResponseTime(parser, method, respTime) } } -func (me *MultiMetricsEngine) RecordXMLParserResponseMismatch(method string, bidder string, isMismatch bool) { +func (me *MultiMetricsEngine) RecordXMLParserResponseMismatch(method string, isMismatch bool) { for _, thisME := range *me { - thisME.RecordXMLParserResponseMismatch(method, bidder, isMismatch) + thisME.RecordXMLParserResponseMismatch(method, isMismatch) } } @@ -90,14 +90,6 @@ func (me *MultiMetricsEngine) RecordBadRequest(endpoint string, pubId string, nb } } -// RecordXMLParserResponseTime records execution time for multiple parsers -func (me *NilMetricsEngine) RecordXMLParserResponseTime(parser string, method string, bidder string, respTime time.Duration) { -} - -// RecordXMLParserResponseMismatch as a noop -func (me *NilMetricsEngine) RecordXMLParserResponseMismatch(method string, bidder string, isMismatch bool) { -} - // RecordVASTTagType as a noop func (me *NilMetricsEngine) RecordVASTTagType(biddder, vastTag string) { } @@ -129,3 +121,11 @@ func (me *NilMetricsEngine) RecordPanic(hostname, method string) { // RecordBadRequest as a noop func (me *NilMetricsEngine) RecordBadRequest(endpoint string, pubId string, nbr *openrtb3.NoBidReason) { } + +// RecordXMLParserResponseTime records execution time for multiple parsers +func (me *NilMetricsEngine) RecordXMLParserResponseTime(parser string, method string, respTime time.Duration) { +} + +// RecordXMLParserResponseMismatch as a noop +func (me *NilMetricsEngine) RecordXMLParserResponseMismatch(method string, isMismatch bool) { +} diff --git a/metrics/go_metrics_ow.go b/metrics/go_metrics_ow.go index 8cf915139f1..06eca3819ad 100644 --- a/metrics/go_metrics_ow.go +++ b/metrics/go_metrics_ow.go @@ -55,9 +55,9 @@ func (me *Metrics) RecordBadRequest(endpoint string, pubId string, nbr *openrtb3 } // RecordXMLParserResponseTime records execution time for multiple parsers -func (me *Metrics) RecordXMLParserResponseTime(parser string, method string, bidder string, respTime time.Duration) { +func (me *Metrics) RecordXMLParserResponseTime(parser string, method string, respTime time.Duration) { } // RecordXMLParserResponseMismatch as a noop -func (me *Metrics) RecordXMLParserResponseMismatch(method string, bidder string, isMismatch bool) { +func (me *Metrics) RecordXMLParserResponseMismatch(method string, isMismatch bool) { } diff --git a/metrics/metrics_mock_ow.go b/metrics/metrics_mock_ow.go index dfe5bb97bda..9bbb0d93cb6 100644 --- a/metrics/metrics_mock_ow.go +++ b/metrics/metrics_mock_ow.go @@ -61,11 +61,11 @@ func (me *MetricsEngineMock) RecordBadRequest(endpoint string, pubId string, nbr } // RecordXMLParserResponseTime records execution time for multiple parsers -func (me *MetricsEngineMock) RecordXMLParserResponseTime(parser string, method string, bidder string, respTime time.Duration) { - me.Called(parser, method, bidder, respTime) +func (me *MetricsEngineMock) RecordXMLParserResponseTime(parser string, method string, respTime time.Duration) { + me.Called(parser, method, respTime) } // RecordXMLParserResponseMismatch mock -func (me *MetricsEngineMock) RecordXMLParserResponseMismatch(method string, bidder string, isMismatch bool) { - me.Called(method, bidder, isMismatch) +func (me *MetricsEngineMock) RecordXMLParserResponseMismatch(method string, isMismatch bool) { + me.Called(method, isMismatch) } diff --git a/metrics/metrics_ow.go b/metrics/metrics_ow.go index 6c36854ac9c..33d910a0cff 100644 --- a/metrics/metrics_ow.go +++ b/metrics/metrics_ow.go @@ -22,7 +22,7 @@ type OWMetricsEngine interface { RecordPanic(hostname, method string) RecordBadRequest(endpoint string, pubId string, nbr *openrtb3.NoBidReason) //RecordXMLParserResponseTime records execution time for multiple parsers - RecordXMLParserResponseTime(parser string, method string, bidder string, respTime time.Duration) + RecordXMLParserResponseTime(parser string, method string, respTime time.Duration) //RecordXMLParserResponseMismatch records number of response mismatch - RecordXMLParserResponseMismatch(method string, bidder string, isMismatch bool) + RecordXMLParserResponseMismatch(method string, isMismatch bool) } diff --git a/metrics/prometheus/prometheus_ow.go b/metrics/prometheus/prometheus_ow.go index a74dbe198cb..66ae5669ee4 100644 --- a/metrics/prometheus/prometheus_ow.go +++ b/metrics/prometheus/prometheus_ow.go @@ -220,24 +220,22 @@ func (m *Metrics) RecordHttpCounter() { } // RecordXMLParserResponseTime records xml parser response time -func (m *OWMetrics) RecordXMLParserResponseTime(parser string, method string, bidder string, respTime time.Duration) { +func (m *OWMetrics) RecordXMLParserResponseTime(parser string, method string, respTime time.Duration) { m.xmlParserResponseTime.With(prometheus.Labels{ xmlParserLabel: parser, methodLabel: method, - adapterLabel: bidder, - }).Observe(respTime.Seconds()) + }).Observe(float64(respTime.Microseconds())) } // RecordVastVersion record the count of vast version labelled by bidder and vast version -func (m *OWMetrics) RecordXMLParserResponseMismatch(method, bidder string, isMismatch bool) { +func (m *OWMetrics) RecordXMLParserResponseMismatch(method string, isMismatch bool) { status := requestSuccessful if isMismatch { status = requestFailed } m.xmlParserMismatch.With(prometheus.Labels{ - methodLabel: method, - adapterLabel: bidder, - statusLabel: status, + methodLabel: method, + statusLabel: status, }).Inc() } @@ -327,12 +325,12 @@ func (m *OWMetrics) init(cfg config.PrometheusMetrics, reg *prometheus.Registry) //XML Parser Response Time m.xmlParserResponseTime = newHistogramVec(cfg, reg, "xml_parser_response_time", - "Time taken by xml parser", []string{xmlParserLabel, methodLabel, adapterLabel}, - //0.01ms, 0.5ms, 1ms, 5ms, 10ms - []float64{0.0001, 0.0005, 0.001, 0.005, 0.01}) + "Time taken by xml parser", []string{xmlParserLabel, methodLabel}, + //50µs, 100µs, 250µs, 500µs, 1ms, 5ms, 10ms + []float64{50, 100, 250, 500, 1000, 5000, 10000}) m.xmlParserMismatch = newCounter(cfg, reg, "etree_fastxml_resp_mismatch", "Count of no of bids for which fast xml and etree response mismatch", - []string{methodLabel, adapterLabel, statusLabel}) + []string{methodLabel, statusLabel}) } diff --git a/metrics/prometheus/prometheus_ow_test.go b/metrics/prometheus/prometheus_ow_test.go index 795dde9770a..f9a218f431a 100644 --- a/metrics/prometheus/prometheus_ow_test.go +++ b/metrics/prometheus/prometheus_ow_test.go @@ -215,8 +215,8 @@ func TestRecordFloorStatus(t *testing.T) { func TestRecordXMLParserResponseMismatch(t *testing.T) { type args struct { - method, bidder string - isMismatch bool + method string + isMismatch bool } type want struct { expCount int @@ -231,7 +231,6 @@ func TestRecordXMLParserResponseMismatch(t *testing.T) { name: "mismatch found", args: args{ method: "xml", - bidder: "bidder", isMismatch: true, }, want: want{ @@ -243,7 +242,6 @@ func TestRecordXMLParserResponseMismatch(t *testing.T) { name: "mismatch not found", args: args{ method: "xml", - bidder: "bidder", isMismatch: false, }, want: want{ @@ -256,16 +254,15 @@ func TestRecordXMLParserResponseMismatch(t *testing.T) { t.Run(tt.name, func(t *testing.T) { pm := createMetricsForTesting() - pm.RecordXMLParserResponseMismatch(tt.args.method, tt.args.bidder, tt.args.isMismatch) + pm.RecordXMLParserResponseMismatch(tt.args.method, tt.args.isMismatch) assertCounterVecValue(t, "", "record dynamic fetch failure", pm.xmlParserMismatch, float64(tt.want.expCount), prometheus.Labels{ - methodLabel: tt.args.method, - adapterLabel: tt.args.bidder, - statusLabel: tt.want.status, + methodLabel: tt.args.method, + statusLabel: tt.want.status, }) }) } From 212b43ae0ae3bc9f864a5894a62b7012e5c64d0b Mon Sep 17 00:00:00 2001 From: Pubmatic-Supriya-Patil <131644110+Pubmatic-Supriya-Patil@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:23:13 +0530 Subject: [PATCH 10/24] OTT-1982: honor IFA over session_id if when ifa_type is absent (#895) --- modules/pubmatic/openwrap/device.go | 2 +- modules/pubmatic/openwrap/device_test.go | 45 +++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/modules/pubmatic/openwrap/device.go b/modules/pubmatic/openwrap/device.go index 899a0c00d78..82dbd9acf2b 100644 --- a/modules/pubmatic/openwrap/device.go +++ b/modules/pubmatic/openwrap/device.go @@ -54,7 +54,7 @@ func updateDeviceIFADetails(dvc *models.DeviceCtx) { } else { deviceExt.DeleteIFAType() } - } else if extSessionID != "" { + } else if extSessionID != "" && dvc.DeviceIFA == "" { dvc.DeviceIFA = extSessionID dvc.IFATypeID = ptrutil.ToPtr(models.DeviceIfaTypeIdSessionId) deviceExt.SetIFAType(models.DeviceIFATypeSESSIONID) diff --git a/modules/pubmatic/openwrap/device_test.go b/modules/pubmatic/openwrap/device_test.go index 6fd88da9b6d..c9b48999951 100644 --- a/modules/pubmatic/openwrap/device_test.go +++ b/modules/pubmatic/openwrap/device_test.go @@ -390,6 +390,27 @@ func TestUpdateDeviceIFADetails(t *testing.T) { }(), }, }, + want: &models.DeviceCtx{ + DeviceIFA: `existing_ifa_id`, + Ext: func() *models.ExtDevice { + deviceExt := &models.ExtDevice{} + deviceExt.SetSessionID(`sample_session_id`) + return deviceExt + }(), + }, + }, + { + name: `ifa_type_missing_ifa_empty_session_id_present`, + args: args{ + dvc: &models.DeviceCtx{ + DeviceIFA: "", + Ext: func() *models.ExtDevice { + deviceExt := &models.ExtDevice{} + deviceExt.SetSessionID(`sample_session_id`) + return deviceExt + }(), + }, + }, want: &models.DeviceCtx{ IFATypeID: ptrutil.ToPtr(9), DeviceIFA: `sample_session_id`, @@ -397,11 +418,33 @@ func TestUpdateDeviceIFADetails(t *testing.T) { deviceExt := &models.ExtDevice{} deviceExt.SetIFAType(models.DeviceIFATypeSESSIONID) deviceExt.SetSessionID(`sample_session_id`) - return deviceExt }(), }, }, + { + name: `ifa_type_missing_ifa_not_present_session_id_present`, + args: args{ + dvc: &models.DeviceCtx{ + Ext: func() *models.ExtDevice { + deviceExt := &models.ExtDevice{} + deviceExt.SetSessionID(`sample_session_id`) + return deviceExt + }(), + }, + }, + want: &models.DeviceCtx{ + IFATypeID: ptrutil.ToPtr(9), + DeviceIFA: `sample_session_id`, + Ext: func() *models.ExtDevice { + deviceExt := &models.ExtDevice{} + deviceExt.SetIFAType(models.DeviceIFATypeSESSIONID) + deviceExt.SetSessionID(`sample_session_id`) + return deviceExt + }(), + }, + }, + // TODO: Add test cases. } for _, tt := range tests { From 82e473075cb91566f060283939c1ae54b7087cbf Mon Sep 17 00:00:00 2001 From: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:23:31 +0530 Subject: [PATCH 11/24] OTT-1824-Fix-Imports (#898) --- endpoints/events/vtrack_ow_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/events/vtrack_ow_test.go b/endpoints/events/vtrack_ow_test.go index ebf81d9f430..d12035186a5 100644 --- a/endpoints/events/vtrack_ow_test.go +++ b/endpoints/events/vtrack_ow_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" - "github.com/PubMatic-OpenWrap/prebid-server/v2/openrtb_ext" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) From cd6c38d3c89dd22fb79d186362f7003b5ac9d8fa Mon Sep 17 00:00:00 2001 From: ashishshinde-pubm <109787960+ashishshinde-pubm@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:38:47 +0530 Subject: [PATCH 12/24] OTT-1807: Fix incorrect pb value for seatNonBid (#899) --- analytics/pubmatic/logger.go | 1 + analytics/pubmatic/logger_test.go | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/analytics/pubmatic/logger.go b/analytics/pubmatic/logger.go index 9a55f4a685e..75364070d55 100644 --- a/analytics/pubmatic/logger.go +++ b/analytics/pubmatic/logger.go @@ -385,6 +385,7 @@ func getPartnerRecordsByImp(ao analytics.AuctionObject, rCtx *models.RequestCtx) price := bid.Price // If bids are rejected before setting bidExt.OriginalBidCPM, calculate the price and ocpm values based on the currency and revshare. price = computeBidPriceForBidsRejectedBeforeSettingOCPM(rCtx, &bidExt, price, revShare, ao) + bid.Price = price if ao.Response.Cur != models.USD { if bidCtx.EN != 0 { // valid-bids + dropped-bids+ default-bids price = bidCtx.EN diff --git a/analytics/pubmatic/logger_test.go b/analytics/pubmatic/logger_test.go index b12bdc8a9bc..41ef74a283f 100644 --- a/analytics/pubmatic/logger_test.go +++ b/analytics/pubmatic/logger_test.go @@ -1297,6 +1297,7 @@ func TestGetPartnerRecordsByImpForDefaultBids(t *testing.T) { } } func TestGetPartnerRecordsByImpForSeatNonBid(t *testing.T) { + pg, _ := openrtb_ext.NewPriceGranularityFromLegacyID("med") type args struct { ao analytics.AuctionObject rCtx *models.RequestCtx @@ -1464,6 +1465,7 @@ func TestGetPartnerRecordsByImpForSeatNonBid(t *testing.T) { }, }, rCtx: &models.RequestCtx{ + PriceGranularity: &pg, CurrencyConversion: func(from, to string, value float64) (float64, error) { if from == "USD" && to == "EUR" { return value * 1.2, nil @@ -1522,6 +1524,7 @@ func TestGetPartnerRecordsByImpForSeatNonBid(t *testing.T) { OriginalCur: "EUR", FloorValue: 10.5, FloorRuleValue: 10.5, + PriceBucket: "8.00", Nbr: ptrutil.ToPtr(nbr.LossBidLostInVastUnwrap), }, }, @@ -1561,6 +1564,7 @@ func TestGetPartnerRecordsByImpForSeatNonBid(t *testing.T) { }, }, rCtx: &models.RequestCtx{ + PriceGranularity: &pg, CurrencyConversion: func(from, to string, value float64) (float64, error) { if from == "USD" && to == "EUR" { return value * 1.2, nil @@ -1611,6 +1615,7 @@ func TestGetPartnerRecordsByImpForSeatNonBid(t *testing.T) { PartnerSize: "10x50", GrossECPM: 8, NetECPM: 4, + PriceBucket: "4.00", BidID: "bid-id-1", OrigBidID: "bid-id-1", DealID: "-1", From cfc54e4e22a52690877c64d4960c61172c828a41 Mon Sep 17 00:00:00 2001 From: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:44:28 +0530 Subject: [PATCH 13/24] OTT-1824-P31 Adding fastxml_enabled_percentage (#900) --- adapters/vastbidder/vastbidder.go | 18 +- adapters/vastbidder/vastbidder_test.go | 2 +- config/config.go | 8 +- config/config_ow.go | 8 +- endpoints/events/test/base64_vast.txt.tar.gz | Bin 171 -> 0 bytes endpoints/events/test/ow_failed.txt | 0 endpoints/events/test/vast.txt | 66 --- endpoints/events/vtrack_ow.go | 20 +- endpoints/events/vtrack_ow_test.go | 72 ++- exchange/adapter_util.go | 2 +- exchange/events_ow.go | 9 +- exchange/exchange.go | 8 +- exchange/exchange_ow.go | 2 +- exchange/exchange_ow_test.go | 2 +- go.mod | 2 +- go.sum | 438 +------------------ openrtb_ext/fastxml_ow.go | 241 ++++++++++ 17 files changed, 336 insertions(+), 562 deletions(-) delete mode 100644 endpoints/events/test/base64_vast.txt.tar.gz create mode 100644 endpoints/events/test/ow_failed.txt delete mode 100644 endpoints/events/test/vast.txt create mode 100644 openrtb_ext/fastxml_ow.go diff --git a/adapters/vastbidder/vastbidder.go b/adapters/vastbidder/vastbidder.go index b6a4897f10a..778b809ba96 100644 --- a/adapters/vastbidder/vastbidder.go +++ b/adapters/vastbidder/vastbidder.go @@ -12,9 +12,9 @@ import ( // VASTBidder is default implementation of ITagBidder type VASTBidder struct { adapters.Bidder - bidderName openrtb_ext.BidderName - adapterConfig *config.Adapter - fastXMLExperiment bool + bidderName openrtb_ext.BidderName + adapterConfig *config.Adapter + fastXMLEnabledPercentage int } // MakeRequests will contains default definition for processing queries @@ -76,7 +76,7 @@ func (a *VASTBidder) MakeBids(internalRequest *openrtb2.BidRequest, externalRequ responseData, errs := handler.MakeBids() - if a.fastXMLExperiment && len(errs) == 0 { + if openrtb_ext.IsFastXMLEnabled(a.fastXMLEnabledPercentage) && len(errs) == 0 { a.fastXMLTesting( newResponseHandler(internalRequest, externalRequest, response, getXMLParser(fastXMLParserType)), responseData, @@ -111,16 +111,16 @@ func (a *VASTBidder) fastXMLTesting(handler *responseHandler, responseData *adap } // NewTagBidder is an constructor for TagBidder -func NewTagBidder(bidderName openrtb_ext.BidderName, config config.Adapter, enableFastXML bool) *VASTBidder { +func NewTagBidder(bidderName openrtb_ext.BidderName, config config.Adapter, enableFastXML int) *VASTBidder { obj := &VASTBidder{ - bidderName: bidderName, - adapterConfig: &config, - fastXMLExperiment: enableFastXML, + bidderName: bidderName, + adapterConfig: &config, + fastXMLEnabledPercentage: enableFastXML, } return obj } // Builder builds a new instance of the 33Across adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, serverConfig config.Server) (adapters.Bidder, error) { - return NewTagBidder(bidderName, config, serverConfig.EnableFastXML), nil + return NewTagBidder(bidderName, config, serverConfig.FastXMLEnabledPercentage), nil } diff --git a/adapters/vastbidder/vastbidder_test.go b/adapters/vastbidder/vastbidder_test.go index f53abe23209..6f7652e8519 100644 --- a/adapters/vastbidder/vastbidder_test.go +++ b/adapters/vastbidder/vastbidder_test.go @@ -137,7 +137,7 @@ func TestMakeRequests(t *testing.T) { RegisterNewBidderMacro(bidderName, func() IBidderMacro { return newMyVastBidderMacro(tt.args.customHeaders) }) - bidder := NewTagBidder(bidderName, config.Adapter{}, false) + bidder := NewTagBidder(bidderName, config.Adapter{}, 0) reqData, err := bidder.MakeRequests(tt.args.req, nil) assert.Nil(t, err) for _, req := range reqData { diff --git a/config/config.go b/config/config.go index bf98f35f406..e9f200a8341 100644 --- a/config/config.go +++ b/config/config.go @@ -675,10 +675,10 @@ type Debug struct { } type Server struct { - ExternalUrl string - GvlID int - DataCenter string - EnableFastXML bool + ExternalUrl string + GvlID int + DataCenter string + FastXMLEnabledPercentage int } func (server *Server) Empty() bool { diff --git a/config/config_ow.go b/config/config_ow.go index 562208ba0ca..5121f1f6095 100644 --- a/config/config_ow.go +++ b/config/config_ow.go @@ -2,10 +2,10 @@ package config type OpenWrapConfig struct { // OpenWrap Configurations - EnableFastXML bool `mapstructure:"enable_fast_xml"` - TrackerURL string `mapstructure:"tracker_url"` - VendorListScheduler VendorListScheduler `mapstructure:"vendor_list_scheduler"` - PriceFloorFetcher PriceFloorFetcher `mapstructure:"price_floor_fetcher"` + FastXMLEnabledPercentage int `mapstructure:"fast_xml_enabled_percentage"` + TrackerURL string `mapstructure:"tracker_url"` + VendorListScheduler VendorListScheduler `mapstructure:"vendor_list_scheduler"` + PriceFloorFetcher PriceFloorFetcher `mapstructure:"price_floor_fetcher"` } type PriceFloorFetcher struct { diff --git a/endpoints/events/test/base64_vast.txt.tar.gz b/endpoints/events/test/base64_vast.txt.tar.gz deleted file mode 100644 index d2b6fb7105258b1e559d3af94a76c11ed9957d52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmV;c095}UiwFRxSjc7o153?IDag;vD=F4bElUMaC8@w5;4 Zfp*#`7zLwX6pR8I0s!aS2`~T%001MRIUxW5 diff --git a/endpoints/events/test/ow_failed.txt b/endpoints/events/test/ow_failed.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/endpoints/events/test/vast.txt b/endpoints/events/test/vast.txt deleted file mode 100644 index 24cc528359a..00000000000 --- a/endpoints/events/test/vast.txt +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - -00:00:26 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/endpoints/events/vtrack_ow.go b/endpoints/events/vtrack_ow.go index 0906b8aa5d9..28b35eb8b0c 100644 --- a/endpoints/events/vtrack_ow.go +++ b/endpoints/events/vtrack_ow.go @@ -4,13 +4,11 @@ import ( "bytes" "encoding/base64" "errors" - "math/rand" "strings" "time" "github.com/PubMatic-OpenWrap/fastxml" "github.com/beevik/etree" - "github.com/golang/glog" "github.com/prebid/openrtb/v20/adcom1" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/openrtb_ext" @@ -60,16 +58,13 @@ func InjectVideoEventTrackers( //temporary if fastXMLResponse != vastXML { - fastXMLResponse = strings.ReplaceAll(fastXMLResponse, " >", ">") + fastXMLResponse = tmpFastXMLProcessing(fastXMLResponse) } isResponseMismatch := (response != fastXMLResponse) if isResponseMismatch { - random := rand.Int() - glog.V(2).Infof("[XML_PARSER_TEST] method:[vcr] rand:[%v] creative:[%s]", random, base64.StdEncoding.EncodeToString([]byte(vastXML))) - //glog.V(2).Infof("[XML_PARSER_TEST] method:[vcr] rand:[%v] etree:[%s]", random, base64.StdEncoding.EncodeToString([]byte(response))) - //glog.V(2).Infof("[XML_PARSER_TEST] method:[vcr] rand:[%v] fastxml:[%s]", random, base64.StdEncoding.EncodeToString([]byte(fastXMLResponse))) + openrtb_ext.FastXMLLogf("\n[XML_PARSER_TEST] method:[vcr] creative:[%s]", base64.StdEncoding.EncodeToString([]byte(vastXML))) } metrics = &openrtb_ext.FastXMLMetrics{ @@ -82,6 +77,17 @@ func InjectVideoEventTrackers( return response, metrics, err } +func tmpFastXMLProcessing(vast string) string { + //replace only if trackers are injected + vast = strings.ReplaceAll(vast, " >", ">") + // if strings.Contains(vast, "'") { + // if index := strings.Index(vast, " 0 { - if debugLines[line] == false { - continue - } + if len(debugLines) > 0 && sort.SearchInts(debugLines, line) == len(debugLines) { + continue } + if base64Decode { data, err := base64.StdEncoding.DecodeString(vast) if !assert.Nil(t, err) { @@ -486,8 +487,7 @@ func TestCompareXMLParsers(t *testing.T) { etreeXML, _ := injectVideoEventsETree(vast, eventURLMap, false, adcom1.LinearityLinear) fastXML, _ := injectVideoEventsFastXML(vast, eventURLMap, false, adcom1.LinearityLinear) if vast != fastXML { - //replace only if trackers are injected - fastXML = strings.ReplaceAll(fastXML, " >", ">") + fastXML = tmpFastXMLProcessing(fastXML) } if !assert.Equal(t, etreeXML, fastXML) { @@ -495,25 +495,51 @@ func TestCompareXMLParsers(t *testing.T) { } }) } - t.Logf("\n total:[%v] mismatched:[%v] lines:[%v]", line, len(mismatched), mismatched) + t.Logf("\ntotal:[%v] mismatched:[%v] lines:[%v]", line, len(mismatched), mismatched) assert.Equal(t, 0, len(mismatched)) assert.Nil(t, scanner.Err()) } -func TestCompare(t *testing.T) { - vastBytes, err := os.ReadFile(`./test/vast.txt`) - assert.NoError(t, err) +func TestBase64(t *testing.T) { + fileName := `./test/ow_failed.txt` + + file, err := os.Open(fileName) + if !assert.Nil(t, err) { + return + } + + defer file.Close() + var mismatched, errored, debugLines []int + var line, singleQuotePresent, maxLength int + + maxLength = 14884 + scanner := bufio.NewScanner(file) + scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024) - vast := string(vastBytes) - etreeXML, err := injectVideoEventsETree(vast, eventURLMap, false, adcom1.LinearityLinear) - assert.NoError(t, err) + //debugLines = []int{19, 24, 25, 29, 58, 80, 83, 84, 86, 93, 128, 147, 151, 155, 159, 168, 184, 190, 199, 200, 225, 226, 243, 249, 254, 261, 272, 281, 291, 298, 310, 312, 320, 323, 328, 340, 350, 358, 362, 373, 376, 384} + sort.Ints(debugLines) - fastXML, err := injectVideoEventsFastXML(vast, eventURLMap, false, adcom1.LinearityLinear) - assert.NoError(t, err) + for scanner.Scan() { + line++ + value := scanner.Text() - if vast != fastXML { - //replace only if trackers are injected - fastXML = strings.ReplaceAll(fastXML, " >", ">") + if len(debugLines) > 0 && sort.SearchInts(debugLines, line) == len(debugLines) { + continue + } + + vast, err := base64.RawStdEncoding.DecodeString(value[0:maxLength]) + + if err != nil { + errored = append(errored, line) + continue + } + + if bytes.Contains(vast, []byte("'")) { + singleQuotePresent++ + } else { + mismatched = append(mismatched, line) + } } - assert.Equal(t, etreeXML, fastXML) + assert.Empty(t, mismatched) + assert.Empty(t, errored) } diff --git a/exchange/adapter_util.go b/exchange/adapter_util.go index 2412fb314fe..dc6b1a8753f 100644 --- a/exchange/adapter_util.go +++ b/exchange/adapter_util.go @@ -11,7 +11,7 @@ import ( ) func BuildAdapters(client *http.Client, cfg *config.Configuration, infos config.BidderInfos, me metrics.MetricsEngine) (map[openrtb_ext.BidderName]AdaptedBidder, []error) { - server := config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter, EnableFastXML: cfg.EnableFastXML} + server := config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter, FastXMLEnabledPercentage: cfg.FastXMLEnabledPercentage} bidders, errs := buildBidders(infos, newAdapterBuilders(), server) if len(errs) > 0 { diff --git a/exchange/events_ow.go b/exchange/events_ow.go index f0a881a61d4..61e45e9e336 100644 --- a/exchange/events_ow.go +++ b/exchange/events_ow.go @@ -4,12 +4,13 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/endpoints/events" "github.com/prebid/prebid-server/v2/metrics" + "github.com/prebid/prebid-server/v2/openrtb_ext" ) type OpenWrapEventTracking struct { - enabledVideoEvents bool - enableFastXML bool - me metrics.MetricsEngine + enabledVideoEvents bool + fastXMLEnabledPercentage int + me metrics.MetricsEngine } func (ev *eventTracking) injectVideoEvents( @@ -22,7 +23,7 @@ func (ev *eventTracking) injectVideoEvents( } // always inject event trackers without checkign isModifyingVASTXMLAllowed - newVastXML, metrics, err := events.InjectVideoEventTrackers(bidRequest, bid, vastXML, trackerURL, bidID, requestingBidder, bidderCoreName, ev.auctionTimestampMs, ev.enableFastXML) + newVastXML, metrics, err := events.InjectVideoEventTrackers(bidRequest, bid, vastXML, trackerURL, bidID, requestingBidder, bidderCoreName, ev.auctionTimestampMs, openrtb_ext.IsFastXMLEnabled(ev.fastXMLEnabledPercentage)) if err == nil { bid.AdM = newVastXML } diff --git a/exchange/exchange.go b/exchange/exchange.go index 9d66d19acc1..29ed299a87d 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -176,7 +176,7 @@ func NewExchange(adapters map[openrtb_ext.BidderName]AdaptedBidder, cache prebid bidIDGenerator: &bidIDGenerator{cfg.GenerateBidID}, hostSChainNode: cfg.HostSChainNode, adsCertSigner: adsCertSigner, - server: config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter, EnableFastXML: cfg.EnableFastXML}, + server: config.Server{ExternalUrl: cfg.ExternalURL, GvlID: cfg.GDPR.HostVendorID, DataCenter: cfg.DataCenter, FastXMLEnabledPercentage: cfg.FastXMLEnabledPercentage}, bidValidationEnforcement: cfg.Validations, requestSplitter: requestSplitter, macroReplacer: macroReplacer, @@ -495,9 +495,9 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog evTracking := getEventTracking(requestExtPrebid, r.StartTime, &r.Account, e.bidderInfo, e.externalURL, OpenWrapEventTracking{ - enabledVideoEvents: requestExtPrebid == nil || !requestExtPrebid.ExtOWRequestPrebid.TrackerDisabled, - enableFastXML: e.server.EnableFastXML, - me: e.me, + enabledVideoEvents: requestExtPrebid == nil || !requestExtPrebid.ExtOWRequestPrebid.TrackerDisabled, + fastXMLEnabledPercentage: e.server.FastXMLEnabledPercentage, + me: e.me, }) adapterBids = evTracking.modifyBidsForEvents(adapterBids, r.BidRequestWrapper.BidRequest, e.trakerURL) diff --git a/exchange/exchange_ow.go b/exchange/exchange_ow.go index 38ddd84c57b..fc9c52e9d72 100644 --- a/exchange/exchange_ow.go +++ b/exchange/exchange_ow.go @@ -205,7 +205,7 @@ func recordOpenWrapBidResponseMetrics(bidder *bidderAdapter, bidResponse *adapte recordFastXMLMetrics(bidder.me, "vastbidder", bidResponse.FastXMLMetrics) if bidResponse.FastXMLMetrics.IsRespMismatch { resp, _ := jsonutil.Marshal(bidResponse) - glog.V(2).Infof("\n[XML_PARSER_TEST] method:[vast_bidder] response:[%s]", resp) + openrtb_ext.FastXMLLogf("\n[XML_PARSER_TEST] method:[vast_bidder] response:[%s]", resp) } } diff --git a/exchange/exchange_ow_test.go b/exchange/exchange_ow_test.go index 78ebf3dff1f..6a4337aad3c 100644 --- a/exchange/exchange_ow_test.go +++ b/exchange/exchange_ow_test.go @@ -680,7 +680,7 @@ func TestNormalizeDomain(t *testing.T) { func newTestTagAdapter(name string) *bidderAdapter { return &bidderAdapter{ - Bidder: vastbidder.NewTagBidder(openrtb_ext.BidderName(name), config.Adapter{}, false), + Bidder: vastbidder.NewTagBidder(openrtb_ext.BidderName(name), config.Adapter{}, 0), BidderName: openrtb_ext.BidderName(name), } } diff --git a/go.mod b/go.mod index 2ef398dec75..4fcbd4a1f1c 100644 --- a/go.mod +++ b/go.mod @@ -100,6 +100,6 @@ replace github.com/prebid/prebid-server/v2 => ./ replace github.com/prebid/openrtb/v20 => github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef -replace github.com/beevik/etree v1.0.2 => github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240721064252-bb63229a1baa +replace github.com/beevik/etree v1.0.2 => github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240909135535-5d3df9e9a959 replace github.com/beevik/etree/110 => github.com/beevik/etree v1.1.0 diff --git a/go.sum b/go.sum index 54f721ef026..50bc4a5977d 100644 --- a/go.sum +++ b/go.sum @@ -29,271 +29,25 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go/accessapproval v1.6.0 h1:x0cEHro/JFPd7eS4BlEWNTMecIj2HdXjOVB5BtvwER0= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accesscontextmanager v1.7.0 h1:MG60JgnEoawHJrbWw0jGdv6HLNSf6gQvYRiXpuzqgEA= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/aiplatform v1.37.0 h1:zTw+suCVchgZyO+k847wjzdVjWmrAuehxdvcZvJwfGg= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/analytics v0.19.0 h1:LqAo3tAh2FU9+w/r7vc3hBjU23Kv7GhO/PDIW7kIYgM= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/apigateway v1.5.0 h1:ZI9mVO7x3E9RK/BURm2p1aw9YTBSCQe3klmyP1WxWEg= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigeeconnect v1.5.0 h1:sWOmgDyAsi1AZ48XRHcATC0tsi9SkPT7DA/+VCfkaeA= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeregistry v0.6.0 h1:E43RdhhCxdlV+I161gUY2rI4eOaMzHTA5kNkvRsFXvc= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apikeys v0.6.0 h1:B9CdHFZTFjVti89tmyXXrO+7vSNo2jvZuHG8zD5trdQ= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.7.1 h1:aBGDKmRIaRRoWJ2tAoN0oVSHoWLhtO9aj/NvUyP4aYs= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/area120 v0.7.1 h1:ugckkFh4XkHJMPhTIx0CyvdoBxmOpMe8rNs4Ok8GAag= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/artifactregistry v1.13.0 h1:o1Q80vqEB6Qp8WLEH3b8FBLNUCrGQ4k5RFj0sn/sgO8= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/asset v1.13.0 h1:YAsssO08BqZ6mncbb6FPlj9h6ACS7bJQUOlzciSfbNk= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/assuredworkloads v1.10.0 h1:VLGnVFta+N4WM+ASHbhc14ZOItOabDLH1MSoDv+Xuag= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/automl v1.12.0 h1:50VugllC+U4IGl3tDNcZaWvApHBTrn/TvyHDJ0wM+Uw= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/baremetalsolution v0.5.0 h1:2AipdYXL0VxMboelTTw8c1UJ7gYu35LZYUbuRv9Q28s= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/batch v0.7.0 h1:YbMt0E6BtqeD5FvSv1d56jbVsWEzlGm55lYte+M6Mzs= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/beyondcorp v0.5.0 h1:UkY2BTZkEUAVrgqnSdOJ4p3y9ZRBPEe1LkjgC8Bj/Pc= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.50.0 h1:RscMV6LbnAmhAzD893Lv9nXXy2WCaJmbxYPWDLbGqNQ= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/billing v1.13.0 h1:JYj28UYF5w6VBAh0gQYlgHJ/OD1oA+JgW29YZQU+UHM= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/binaryauthorization v1.5.0 h1:d3pMDBCCNivxt5a4eaV7FwL7cSH0H7RrEnFrTb1QKWs= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/certificatemanager v1.6.0 h1:5C5UWeSt8Jkgp7OWn2rCkLmYurar/vIWIoSQ2+LaTOc= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/channel v1.12.0 h1:GpcQY5UJKeOekYgsX3QXbzzAc/kRGtBq43fTmyKe6Uw= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/cloudbuild v1.9.0 h1:GHQCjV4WlPPVU/j3Rlpc8vNIDwThhd1U9qSY/NPZdko= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/clouddms v1.5.0 h1:E7v4TpDGUyEm1C/4KIrpVSOCTm0P6vWdHT0I4mostRA= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/cloudtasks v1.10.0 h1:uK5k6abf4yligFgYFnG0ni8msai/dSv6mDmiBulU0hU= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.6.0 h1:jXIpfcH/VYSE1SYcPzO0n1VVb+sAamiLOgCw45JbOQk= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/container v1.15.0 h1:NKlY/wCDapfVZlbVVaeuu2UZZED5Dy1z4Zx1KhEzm8c= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/containeranalysis v0.9.0 h1:EQ4FFxNaEAg8PqQCO7bVQfWz9NVwZCUKaM1b3ycfx3U= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/datacatalog v1.13.0 h1:4H5IJiyUE0X6ShQBqgFFZvGGcrwGVndTwUSLP4c52gw= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/dataflow v0.8.0 h1:eYyD9o/8Nm6EttsKZaEGD84xC17bNgSKCu0ZxwqUbpg= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataform v0.7.0 h1:Dyk+fufup1FR6cbHjFpMuP4SfPiF3LI3JtoIIALoq48= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/datafusion v1.6.0 h1:sZjRnS3TWkGsu1LjYPFD/fHeMLZNXDK6PDHi2s2s/bk= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datalabeling v0.7.0 h1:ch4qA2yvddGRUrlfwrNJCr79qLqhS9QBwofPHfFlDIk= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/dataplex v1.6.0 h1:RvoZ5T7gySwm1CHzAw7yY1QwwqaGswunmqEssPxU/AM= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataqna v0.7.0 h1:yFzi/YU4YAdjyo7pXkBE2FeHbgz5OQQBVDdbErEHmVQ= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.11.0 h1:iF6I/HaLs3Ado8uRKMvZRvF/ZLkWaWE9i8AiHzbC774= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastream v1.7.0 h1:BBCBTnWMDwwEzQQmipUXxATa7Cm7CA/gKjKcR2w35T0= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/deploy v1.8.0 h1:otshdKEbmsi1ELYeCKNYppwV0UH5xD05drSdBm7ouTk= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/dialogflow v1.32.0 h1:uVlKKzp6G/VtSW0E7IH1Y5o0H48/UOCmqksG2riYCwQ= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dlp v1.9.0 h1:1JoJqezlgu6NWCroBxr4rOZnwNFILXr4cB9dMaSKO4A= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/documentai v1.18.0 h1:KM3Xh0QQyyEdC8Gs2vhZfU+rt6OCPF0dwVwxKgLmWfI= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/domains v0.8.0 h1:2ti/o9tlWL4N+wIuWUNH+LbfgpwxPr8J1sv9RHA4bYQ= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/edgecontainer v1.0.0 h1:O0YVE5v+O0Q/ODXYsQHmHb+sYM8KNjGZw2pjX2Ws41c= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/errorreporting v0.3.0 h1:kj1XEWMu8P0qlLhm3FwcaFsUvXChV/OraZwA70trRR0= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.5.0 h1:gIzEhCoOT7bi+6QZqZIzX1Erj4SswMPIteNvYVlu+pM= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/eventarc v1.11.0 h1:fsJmNeqvqtk74FsaVDU6cH79lyZNCYP8Rrv7EhaB/PU= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/filestore v1.6.0 h1:ckTEXN5towyTMu4q0uQ1Mde/JwTHur0gXs8oaIZnKfw= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/functions v1.13.0 h1:pPDqtsXG2g9HeOQLoquLbmvmb82Y4Ezdo1GXuotFoWg= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/gaming v1.9.0 h1:7vEhFnZmd931Mo7sZ6pJy7uQPDxF7m7v8xtBheG08tc= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gkebackup v0.4.0 h1:za3QZvw6ujR0uyqkhomKKKNoXDyqYGPJies3voUK8DA= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkeconnect v0.7.0 h1:gXYKciHS/Lgq0GJ5Kc9SzPA35NGc3yqu6SkjonpEr2Q= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkehub v0.12.0 h1:TqCSPsEBQ6oZSJgEYZ3XT8x2gUadbvfwI32YB0kuHCs= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkemulticloud v0.5.0 h1:8I84Q4vl02rJRsFiinBxl7WCozfdLlUVBQuSrqr9Wtk= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/gsuiteaddons v1.5.0 h1:1mvhXqJzV0Vg5Fa95QwckljODJJfDFXV4pn+iL50zzA= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iap v1.7.1 h1:PxVHFuMxmSZyfntKXHXhd8bo82WJ+LcATenq7HLdVnU= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/ids v1.3.0 h1:fodnCDtOXuMmS8LTC2y3h8t24U8F3eKWfhi+3LY6Qf0= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/iot v1.6.0 h1:39W5BFSarRNZfVG0eXI5LYux+OVQT8GkgpHCnrZL2vM= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/kms v1.10.1 h1:7hm1bRqGCA1GBRQUrp831TwJ9TWhP+tvLuP497CQS2g= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/language v1.9.0 h1:7Ulo2mDk9huBoBi8zCE3ONOoBrL6UXfAI71CLQ9GEIM= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/lifesciences v0.8.0 h1:uWrMjWTsGjLZpCTWEAzYvyXj+7fhiZST45u9AgasasI= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5I= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/managedidentities v1.5.0 h1:ZRQ4k21/jAhrHBVKl/AY7SjgzeJwG1iZa+mJ82P+VNg= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/maps v0.7.0 h1:mv9YaczD4oZBZkM5XJl6fXQ984IkJNHPwkc8MUsdkBo= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/mediatranslation v0.7.0 h1:anPxH+/WWt8Yc3EdoEJhPMBRF7EhIdz426A+tuoA0OU= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/memcache v1.9.0 h1:8/VEmWCpnETCrBwS3z4MhT+tIdKgR1Z4Tr2tvYH32rg= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/metastore v1.10.0 h1:QCFhZVe2289KDBQ7WxaHV2rAmPrmRAdLC6gbjUd3HPo= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/monitoring v1.13.0 h1:2qsrgXGVoRXpP7otZ14eE1I568zAa92sJSDPyOJvwjM= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/networkconnectivity v1.11.0 h1:ZD6b4Pk1jEtp/cx9nx0ZYcL3BKqDa+KixNDZ6Bjs1B8= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkmanagement v1.6.0 h1:8KWEUNGcpSX9WwZXq7FtciuNGPdPdPN/ruDm769yAEM= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networksecurity v0.8.0 h1:sOc42Ig1K2LiKlzG71GUVloeSJ0J3mffEBYmvu+P0eo= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/notebooks v1.8.0 h1:Kg2K3K7CbSXYJHZ1aGQpf1xi5x2GUvQWf2sFVuiZh8M= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/optimization v1.3.1 h1:dj8O4VOJRB4CUwZXdmwNViH1OtI0WtWL867/lnYH248= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/orchestration v1.6.0 h1:Vw+CEXo8M/FZ1rb4EjcLv0gJqqw89b7+g+C/EmniTb8= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orgpolicy v1.10.0 h1:XDriMWug7sd0kYT1QKofRpRHzjad0bK8Q8uA9q+XrU4= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/osconfig v1.11.0 h1:PkSQx4OHit5xz2bNyr11KGcaFccL5oqglFPdTboyqwQ= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/oslogin v1.9.0 h1:whP7vhpmc+ufZa90eVpkfbgzJRK/Xomjz+XCD4aGwWw= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/phishingprotection v0.7.0 h1:l6tDkT7qAEV49MNEJkEJTB6vOO/onbSOcNtAT09HPuA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/policytroubleshooter v1.6.0 h1:yKAGC4p9O61ttZUswaq9GAn1SZnEzTd0vUYXD7ZBT7Y= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/privatecatalog v0.8.0 h1:EPEJ1DpEGXLDnmc7mnCAqFmkwUJbIsaLAiLHVOkkwtc= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.30.0 h1:vCge8m7aUKBJYOgrZp7EsNDf6QMd2CAlXZqWTn3yq6s= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsublite v1.7.0 h1:cb9fsrtpINtETHiJ3ECeaVzrfIVhcGjhhJEjybHXHao= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0 h1:6iOCujSNJ0YS7oNymI64hXsjGq60T4FK1zdLugxbzvU= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recommendationengine v0.7.0 h1:VibRFCwWXrFebEWKHfZAt2kta6pS7Tlimsnms0fjv7k= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommender v1.9.0 h1:ZnFRY5R6zOVk2IDS1Jbv5Bw+DExCI5rFumsTnMXiu/A= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/redis v1.11.0 h1:JoAd3SkeDt3rLFAAxEvw6wV4t+8y4ZzfZcZmddqphQ8= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/resourcemanager v1.7.0 h1:NRM0p+RJkaQF9Ee9JMnUV9BQ2QBIOq/v8M+Pbv/wmCs= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcesettings v1.5.0 h1:8Dua37kQt27CCWHm4h/Q1XqCF6ByD7Ouu49xg95qJzI= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/retail v1.12.0 h1:1Dda2OpFNzIb4qWgFZjYlpP7sxX3aLeypKG6A3H4Yys= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/run v0.9.0 h1:ydJQo+k+MShYnBfhaRHSZYeD/SQKZzZLAROyfpeD9zw= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/scheduler v1.9.0 h1:NpQAHtx3sulByTLe2dMwWmah8PWgeoieFPpJpArwFV0= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/security v1.13.0 h1:PYvDxopRQBfYAXKAuDpFCKBvDOWPWzp9k/H5nB3ud3o= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/securitycenter v1.19.0 h1:AF3c2s3awNTMoBtMX3oCUoOMmGlYxGOeuXSYHNBkf14= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/servicecontrol v1.11.1 h1:d0uV7Qegtfaa7Z2ClDzr9HJmnbJW7jn0WhZ7wOX6hLE= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.9.0 h1:SJwk0XX2e26o25ObYUORXx6torSFiYgsGkWSkZgkoSU= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicemanagement v1.8.0 h1:fopAQI/IAzlxnVeiKn/8WiV6zKndjFkvi+gzu+NjywY= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.6.0 h1:rXyq+0+RSIm3HFypctp7WoXxIA563rn206CfMWdqXX4= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.6.0 h1:wT0Uw7ib7+AgZST9eCDygwTJn4+bHMDtZo5fh7kGWDU= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/spanner v1.45.0 h1:7VdjZ8zj4sHbDw55atp5dfY6kn1j9sam9DRNpPQhqR4= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/speech v1.15.0 h1:JEVoWGNnTF128kNty7T4aG4eqv2z86yiMJPT9Zjp+iw= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storagetransfer v1.8.0 h1:5T+PM+3ECU3EY2y9Brv0Sf3oka8pKmsCfpQ07+91G9o= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/talent v1.5.0 h1:nI9sVZPjMKiO2q3Uu0KhTDVov3Xrlpt63fghP9XjyEM= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/texttospeech v1.6.0 h1:H4g1ULStsbVtalbZGktyzXzw6jP26RjVGYx9RaYjBzc= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/tpu v1.5.0 h1:/34T6CbSi+kTv5E19Q9zbU/ix8IviInZpzwz3rsFE+A= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/trace v1.9.0 h1:olxC0QHC59zgJVALtgqfD9tGk0lfeCP5/AGXL3Px/no= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/translate v1.7.0 h1:GvLP4oQ4uPdChBmBaUSa/SaZxCdyWELtlAaKzpHsXdA= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/video v1.15.0 h1:upIbnGI0ZgACm58HPjAeBMleW3sl5cT84AbYQ8PWOgM= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/videointelligence v1.10.0 h1:Uh5BdoET8XXqXX2uXIahGb+wTKbLkGH7s4GXR58RrG8= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/vision/v2 v2.7.0 h1:8C8RXUJoflCI4yVdqhTy9tRyygSHmp60aP363z23HKg= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vmmigration v1.6.0 h1:Azs5WKtfOC8pxvkyrDvt7J0/4DYBch0cVbuFfCCFt5k= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmwareengine v0.3.0 h1:b0NBu7S294l0gmtrT0nOJneMYgZapr5x9tVWvgDoVEM= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vpcaccess v1.6.0 h1:FOe6CuiQD3BhHJWt7E8QlbBcaIzVRddupwJlp7eqmn4= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/webrisk v1.8.0 h1:IY+L2+UwxcVm2zayMAtBhZleecdIFLiC+QJMzgb0kT0= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/websecurityscanner v1.5.0 h1:AHC1xmaNMOZtNqxI9Rmm87IJEyPaRkOxeI0gpAacXGk= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/workflows v1.10.0 h1:FfGp9w0cYnaKZJhUOMqCOJCYT/WlvYBfTQhFWV3sRKI= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.pubmatic.com/PubMatic/go-common v0.0.0-20240313090142-97ff3d63b7c3 h1:Ea8zwi1eeX4kqvi9RyyXrizIIRcstM0XBwf8U7NHrno= git.pubmatic.com/PubMatic/go-common v0.0.0-20240313090142-97ff3d63b7c3/go.mod h1:c/I6IcDn4Mtq4mmw8wGJN3v0o10nIMX7VTuQnsalUw0= @@ -301,51 +55,37 @@ git.pubmatic.com/PubMatic/go-netacuity-client v0.0.0-20240104092757-5d6f15e25fe3 git.pubmatic.com/PubMatic/go-netacuity-client v0.0.0-20240104092757-5d6f15e25fe3/go.mod h1:w733mqJnHt0hLR9mIFMzyDR0D94qzc7mFHsuE0tFQho= git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240827084017-0e392d3beb8b h1:7AsXylZJDwq514L8KE0Id079VNfUsDEMUIYMlRYH+0Y= git.pubmatic.com/PubMatic/vastunwrap v0.0.0-20240827084017-0e392d3beb8b/go.mod h1:kcoJf7k+xug8X8fLWmsiKhPnYP+k7RZkfUoUo5QF+KA= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/IABTechLab/adscert v0.34.0 h1:UNM2gMfRPGUbv3KDiLJmy2ajaVCfF3jWqgVKkz8wBu8= github.com/IABTechLab/adscert v0.34.0/go.mod h1:pCLd3Up1kfTrH6kYFUGGeavxIc1f6Tvvj8yJeFRb7mA= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240721064252-bb63229a1baa h1:3tRjI/7/JkTX2tnIvjEbOUTgJJ4rq4oz2hWSU8jvjH8= -github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240721064252-bb63229a1baa/go.mod h1:5Y8qgcuDoy3XXG907UXkGnVTwihF16rXyJa4zRT7hOE= -github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240823084925-e25a796a41bd h1:5IlcLRGtf1EPaVF+ySv7QidGzcwE3xKALhQxMLXOKus= -github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240823084925-e25a796a41bd/go.mod h1:TGGzSA5ziWpfLsKvqOzgdPGEZ7SJIQjHbcJw6lWoyHU= +github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240909135535-5d3df9e9a959 h1:UM0zl3LogmkLc7/ttGDw+UmuWaVUQHcxUop4c/g6yto= +github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240909135535-5d3df9e9a959/go.mod h1:5Y8qgcuDoy3XXG907UXkGnVTwihF16rXyJa4zRT7hOE= github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2 h1:4zaGImZVnKCJudxKfsVNJAqGhCPxbjApAo0QvEThwpw= github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2/go.mod h1:TGGzSA5ziWpfLsKvqOzgdPGEZ7SJIQjHbcJw6lWoyHU= github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef h1:CXsyYtEgZz/0++fiug6QZXrRYG6BBrl9IGveCxsnhiE= github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef/go.mod h1:hLBrA/APkSrxs5MaW639l+y/EAHivDfRagO2TX/wbSc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q= -github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= -github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.36.29 h1:lM1G3AF1+7vzFm0n7hfH8r2+750BTo+6Lo6FtPB7kzk= github.com/aws/aws-sdk-go v1.36.29/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= @@ -357,15 +97,11 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -373,39 +109,26 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chasex/glog v0.0.0-20160217080310-c62392af379c h1:eXqCBUHfmjbeDqcuvzjsd+bM6A+bnwo5N9FVbV6m5/s= github.com/chasex/glog v0.0.0-20160217080310-c62392af379c/go.mod h1:omJZNg0Qu76bxJd+ExohVo8uXzNcGOk2bv7vel460xk= -github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coocood/freecache v1.2.1 h1:/v1CqMq45NFH9mp/Pt142reundeBM0dVUD3osQBeu/U= github.com/coocood/freecache v1.2.1/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj7rthiQ3vk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -423,58 +146,38 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= @@ -482,7 +185,6 @@ github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -514,10 +216,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -534,13 +234,10 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -556,111 +253,67 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7spovjlY= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= -github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU= github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= -github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8= github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -669,34 +322,24 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lyft/protoc-gen-star v0.5.3 h1:zSGLzsUew8RT+ZKPHc3jnf8XLaVyHzTcAFBzHtCNR20= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -718,20 +361,15 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -749,12 +387,10 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -765,27 +401,22 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prebid/go-gdpr v1.12.0 h1:OrjQ7Uc+lCRYaOirQ48jjG/PBMvZsKNAaRTgzxN6iZ0= github.com/prebid/go-gdpr v1.12.0/go.mod h1:mPZAdkRxn+iuSjaUuJAi9+0SppBOdM1PCzv/55UH3pY= @@ -819,37 +450,26 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/vast v0.0.0-20180618195556-06597a11a4c3 h1:PSgAIBGyQP7KW2+EElPsa3qmaya7kCxLSI/GBR176MQ= github.com/rs/vast v0.0.0-20180618195556-06597a11a4c3/go.mod h1:gq4gkWd7KdigGXkRdN5GEgBQYAWDTmD4/U65MdCgLxQ= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/sagikazarmark/crypt v0.9.0 h1:fipzMFW34hFUEc4D7fsLQFtE7yElkpgyS2zruedRdZk= -github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= @@ -858,7 +478,6 @@ github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcD github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -886,7 +505,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/vrischmann/go-metrics-influxdb v0.1.1 h1:xneKFRjsS4BiVYvAKaM/rOlXYd1pGHksnES0ECCJLgo= github.com/vrischmann/go-metrics-influxdb v0.1.1/go.mod h1:q7YC8bFETCYopXRMtUvQQdLaoVhpsEwvQS2zZEYCqg8= @@ -906,19 +524,10 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.6 h1:Cy2qx3npLcYqTKqGJzMypnMv2tiRyifZJ17BlWIWA7A= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.etcd.io/etcd/client/v2 v2.305.6 h1:fIDR0p4KMjw01MJMfUIDWdQbjo06PD6CeYM5z4EHLi0= -go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= -go.etcd.io/etcd/client/v3 v3.5.6 h1:coLs69PWCXE9G4FKquzNaSHrRyMCAXwF+IX1tAPVO8E= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -926,19 +535,10 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -968,7 +568,6 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w= golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -981,10 +580,8 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= @@ -996,8 +593,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1065,8 +660,6 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1078,8 +671,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1166,8 +757,6 @@ golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1183,8 +772,6 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1241,14 +828,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1282,15 +865,12 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.107.0 h1:I2SlFjD8ZWabaIFOfeEDg3pf0BHJDh6iYQ1ic3Yu/UU= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1393,7 +973,6 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1410,31 +989,22 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1454,11 +1024,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/openrtb_ext/fastxml_ow.go b/openrtb_ext/fastxml_ow.go new file mode 100644 index 00000000000..30e55ba11b4 --- /dev/null +++ b/openrtb_ext/fastxml_ow.go @@ -0,0 +1,241 @@ +package openrtb_ext + +import ( + "bufio" + "fmt" + "math/rand" + "os" + "path/filepath" + "runtime/debug" + "sort" + "sync" + "time" + + "github.com/golang/glog" +) + +type RandomGenerator interface { + GenerateIntn(int) int +} + +type RandomNumberGenerator struct{} + +func (RandomNumberGenerator) GenerateIntn(n int) int { + return rand.Intn(n) +} + +var pid = os.Getpid() + +const maxFileSize = 1 * 1024 * 1024 * 1024 +const maxBufferSize = 256 * 1024 +const maxFiles = 10 +const flushInterval = time.Second * time.Duration(300) + +// Writer interface can be used to define variable returned by GetWriter() method +type Writer interface { + Write(data []byte) (int, error) + Sync() error +} + +// FileWriter ... +type FileWriter struct { + mu sync.Mutex + file Writer + fileName string +} + +// NewFileWriter ... +func NewFileWriter(dirPath, fileName, ext string) Writer { + //create directory if not exists + _ = os.MkdirAll(dirPath, 0755) + + writer := &FileWriter{ + mu: sync.Mutex{}, + file: NewBufferFileWriter(dirPath, fileName, ext), + fileName: fileName, + } + + go purge(dirPath, fileName, ext) + go writer.flush(flushInterval) + + return writer +} + +// Flushd ... +func (f *FileWriter) flush(t time.Duration) { + defer func() { + if errInterface := recover(); errInterface != nil { + glog.Infof("Recovered panic \n Error: %v \n StackTrace: %v", errInterface, string(debug.Stack())) + } + }() + + for { + f.Sync() + time.Sleep(t) + } +} + +// Sync ... +func (f *FileWriter) Sync() (err error) { + f.mu.Lock() + err = f.file.Sync() + f.mu.Unlock() + return err +} + +// Write ... +func (f *FileWriter) Write(data []byte) (n int, err error) { + f.mu.Lock() + n, err = f.file.Write(data) + f.mu.Unlock() + return n, err +} + +// purge files +func purge(dirPath, fileName, ext string) { + fileFormat := dirPath + fileName + "*" + ext + for { + _purge(fileFormat, maxFiles) + time.Sleep(flushInterval) + } +} + +func _purge(fileFormat string, maxFiles int) { + defer func() { + if errInterface := recover(); errInterface != nil { + glog.Infof("Recovered panic \n Error: %v \n StackTrace: %v", errInterface, string(debug.Stack())) + } + }() + + files, _ := filepath.Glob(fileFormat) + sort.Strings(files) + + //remove last files + if len(files) <= maxFiles { + //no files to purge + return + } + + //limit files to max files + files = files[:len(files)-maxFiles] + for _, file := range files { + glog.Infof("[purger] filename:[%s]\n", file) + if err := os.Remove(file); err != nil { + glog.Infof("[purger] error:[purge_failed] file:[%s] message:[%s]", file, err.Error()) + //do not delete status file if original file not deleted + continue + } + } +} + +// bufferFileWriter ... +type bufferFileWriter struct { + dirPath, fileName, ext string + + buf *bufio.Writer + file *os.File + nbytes uint64 +} + +func NewBufferFileWriter(dirPath, fileName, ext string) *bufferFileWriter { + writer := &bufferFileWriter{ + dirPath: dirPath, + fileName: fileName, + ext: ext, + } + return writer +} + +// Sync ... +func (b *bufferFileWriter) Sync() (err error) { + if b.buf != nil { + if err = b.buf.Flush(); err != nil { + return err + } + } + if b.file != nil { + if err = b.file.Sync(); err != nil { + return err + } + } + return nil +} + +// Write ... +func (b *bufferFileWriter) Write(data []byte) (int, error) { + if b.file == nil { + //create new file + if err := b.create(time.Now()); err != nil { + return 0, err + } + } + + if b.nbytes+uint64(len(data)) >= maxFileSize { + //rotate file + if err := b.create(time.Now()); err != nil { + return 0, err + } + } + + n, err := b.buf.Write(data) + b.nbytes += uint64(n) + if err != nil { + return 0, err + } + + return n, nil +} + +func (b *bufferFileWriter) create(t time.Time) (err error) { + if b.file != nil { + if err = b.buf.Flush(); err != nil { + return err + } + + if err = b.file.Close(); err != nil { + return err + } + } + + fname := filepath.Join(b.dirPath, fileNameFormat(b.fileName, b.ext, t)) + b.file, err = os.Create(fname) + b.nbytes = 0 + if err != nil { + return err + } + + glog.Infof("[file_writer] type:[new_file] filename:[%s]\n", fname) + b.buf = bufio.NewWriterSize(b.file, int(maxBufferSize)) + return err +} + +func fileNameFormat(name, ext string, t time.Time) string { + return fmt.Sprintf("%s.%04d%02d%02d-%02d%02d%02d.%d%s", + name, + t.Year(), + t.Month(), + t.Day(), + t.Hour(), + t.Minute(), + t.Second(), + pid, + ext) +} + +func IsFastXMLEnabled(enabledPercentage int) bool { + return enabledPercentage > 0 && enabledPercentage >= rg.GenerateIntn(enabledPercentage) +} + +func FastXMLLogf(format string, args ...any) { + if bfw != nil { + fmt.Fprintf(bfw, format, args...) + } +} + +var rg RandomGenerator +var bfw Writer + +func init() { + rg = &RandomNumberGenerator{} + bfw = NewFileWriter(`/var/log/ssheaderbidding/`, `fastxml`, `.txt`) +} From 9e2497f74f57b333dec8dbff649c79a77f4d0344 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:02:37 +0530 Subject: [PATCH 14/24] Fixed panic when connectionType is not available in request (#901) --- modules/pubmatic/openwrap/beforevalidationhook.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/pubmatic/openwrap/beforevalidationhook.go b/modules/pubmatic/openwrap/beforevalidationhook.go index c6cd5c25246..aa4a938e87c 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook.go +++ b/modules/pubmatic/openwrap/beforevalidationhook.go @@ -346,7 +346,13 @@ func (m OpenWrap) handleBeforeValidationHook( m.metricEngine.RecordReqImpsWithContentCount(rCtx.PubIDStr, models.ContentTypeSite) } } - videoAdUnitCtx = adunitconfig.UpdateVideoObjectWithAdunitConfig(rCtx, imp, div, payload.BidRequest.Device.ConnectionType) + + var connectionType *adcom1.ConnectionType + if payload.BidRequest.Device != nil && payload.BidRequest.Device.ConnectionType != nil { + connectionType = payload.BidRequest.Device.ConnectionType + } + + videoAdUnitCtx = adunitconfig.UpdateVideoObjectWithAdunitConfig(rCtx, imp, div, connectionType) if rCtx.Endpoint == models.EndpointAMP && m.pubFeatures.IsAmpMultiformatEnabled(rCtx.PubID) && isVideoEnabledForAMP(videoAdUnitCtx.AppliedSlotAdUnitConfig) { //Iniitalized local imp.Video object to update macros and get mappings in case of AMP request rCtx.AmpVideoEnabled = true From cb7dca403c86a26dae4e52b50a65c8b4b1759ffd Mon Sep 17 00:00:00 2001 From: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:39:44 +0530 Subject: [PATCH 15/24] OTT-1824-P4: updated etree library to return trimmed text (#906) --- adapters/vastbidder/etree_parser.go | 9 ++++----- adapters/vastbidder/etree_parser_test.go | 6 ++++++ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/adapters/vastbidder/etree_parser.go b/adapters/vastbidder/etree_parser.go index ed8163783a5..fcf06a40c98 100644 --- a/adapters/vastbidder/etree_parser.go +++ b/adapters/vastbidder/etree_parser.go @@ -2,7 +2,6 @@ package vastbidder import ( "strconv" - "strings" "github.com/beevik/etree" "github.com/prebid/prebid-server/v2/openrtb_ext" @@ -70,7 +69,7 @@ func (p *etreeXMLParser) GetPricingDetails() (price float64, currency string) { return 0.0, "" } - priceValue, err := strconv.ParseFloat(strings.TrimSpace(node.Text()), 64) + priceValue, err := strconv.ParseFloat(node.TrimmedText(), 64) if nil != err { return 0.0, "" } @@ -89,7 +88,7 @@ func (p *etreeXMLParser) GetAdvertiser() (advertisers []string) { if ext.SelectAttrValue("type", "") == "advertiser" { ele := ext.SelectElement("Advertiser") if ele != nil { - if value := strings.TrimSpace(ele.Text()); len(value) > 0 { + if value := ele.TrimmedText(); len(value) > 0 { advertisers = append(advertisers, value) } } @@ -98,7 +97,7 @@ func (p *etreeXMLParser) GetAdvertiser() (advertisers []string) { case vastVersion4x: if ele := p.adElement.SelectElement("Advertiser"); ele != nil { - if value := strings.TrimSpace(ele.Text()); len(value) > 0 { + if value := ele.TrimmedText(); len(value) > 0 { advertisers = append(advertisers, value) } } @@ -126,7 +125,7 @@ func (p *etreeXMLParser) GetDuration() (int, error) { if node == nil { return 0, errEmptyVideoDuration } - return parseDuration(strings.TrimSpace(node.Text())) + return parseDuration(node.TrimmedText()) } func (p *etreeXMLParser) getAdElement(vast *etree.Element) *etree.Element { diff --git a/adapters/vastbidder/etree_parser_test.go b/adapters/vastbidder/etree_parser_test.go index dd50ded2dad..43b79a46562 100644 --- a/adapters/vastbidder/etree_parser_test.go +++ b/adapters/vastbidder/etree_parser_test.go @@ -342,6 +342,12 @@ func getPricingDetailsTestCases() []struct { wantPrice: 0, wantCurrency: "", }, + { + name: "bug", + vastXML: "\n\t\n\t\t\n\t\t\tPubMatic\n\t\t\tscenario_9\n\t\t\tTest Ad scenario_9\n\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\tTest Advertiser\n\t\t\tIAB1-1\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t8465_scenario_9\n\t\t\t\t\t\n\t\t\t\t\t\t00:00:10\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n ", + wantPrice: 5, + wantCurrency: "USD", + }, // TODO: Add test cases. } } diff --git a/go.mod b/go.mod index 4fcbd4a1f1c..fdf70090dc8 100644 --- a/go.mod +++ b/go.mod @@ -100,6 +100,6 @@ replace github.com/prebid/prebid-server/v2 => ./ replace github.com/prebid/openrtb/v20 => github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef -replace github.com/beevik/etree v1.0.2 => github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240909135535-5d3df9e9a959 +replace github.com/beevik/etree v1.0.2 => github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240914050009-a916f68552f5 replace github.com/beevik/etree/110 => github.com/beevik/etree v1.1.0 diff --git a/go.sum b/go.sum index 50bc4a5977d..51dad9957bb 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/IABTechLab/adscert v0.34.0/go.mod h1:pCLd3Up1kfTrH6kYFUGGeavxIc1f6Tvv github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240909135535-5d3df9e9a959 h1:UM0zl3LogmkLc7/ttGDw+UmuWaVUQHcxUop4c/g6yto= -github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240909135535-5d3df9e9a959/go.mod h1:5Y8qgcuDoy3XXG907UXkGnVTwihF16rXyJa4zRT7hOE= +github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240914050009-a916f68552f5 h1:qNRDZVW/TJI0O4hPVdk5YCl+WxD6alYdaCG0im73lNo= +github.com/PubMatic-OpenWrap/etree v1.0.2-0.20240914050009-a916f68552f5/go.mod h1:5Y8qgcuDoy3XXG907UXkGnVTwihF16rXyJa4zRT7hOE= github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2 h1:4zaGImZVnKCJudxKfsVNJAqGhCPxbjApAo0QvEThwpw= github.com/PubMatic-OpenWrap/fastxml v0.0.0-20240826060652-d9d5d05fdad2/go.mod h1:TGGzSA5ziWpfLsKvqOzgdPGEZ7SJIQjHbcJw6lWoyHU= github.com/PubMatic-OpenWrap/prebid-openrtb/v20 v20.0.0-20240222072752-2d647d1707ef h1:CXsyYtEgZz/0++fiug6QZXrRYG6BBrl9IGveCxsnhiE= From 5d3b3de93f9f3f5fc4360f4346209c9087a9d411 Mon Sep 17 00:00:00 2001 From: Saurabh Narkhede <108730956+pm-saurabh-narkhede@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:59:11 +0530 Subject: [PATCH 16/24] UOE-10822: Prometheus Stat for Bid Recovery (#851) * stat for bid recovery * change buckets * introduce new stat --- .../openwrap/metrics/config/multimetrics.go | 14 +++++++++ .../metrics/config/multimetrics_test.go | 4 +++ modules/pubmatic/openwrap/metrics/metrics.go | 2 ++ .../pubmatic/openwrap/metrics/mock/mock.go | 24 +++++++++++++++ .../openwrap/metrics/prometheus/prometheus.go | 30 +++++++++++++++++++ .../metrics/prometheus/prometheus_test.go | 24 +++++++++++++++ .../openwrap/metrics/stats/tcp_stats.go | 3 ++ 7 files changed, 101 insertions(+) diff --git a/modules/pubmatic/openwrap/metrics/config/multimetrics.go b/modules/pubmatic/openwrap/metrics/config/multimetrics.go index 72a31262ea5..405a15cb20e 100644 --- a/modules/pubmatic/openwrap/metrics/config/multimetrics.go +++ b/modules/pubmatic/openwrap/metrics/config/multimetrics.go @@ -529,3 +529,17 @@ func (me *MultiMetricsEngine) RecordSignalDataStatus(pubid, profileid, signalTyp thisME.RecordSignalDataStatus(pubid, profileid, signalType) } } + +// RecordBidRecoveryStatus across all engines +func (me *MultiMetricsEngine) RecordBidRecoveryStatus(publisher, profile string, success bool) { + for _, thisME := range *me { + thisME.RecordBidRecoveryStatus(publisher, profile, success) + } +} + +// RecordBidRecoveryResponseTime across all engines +func (me *MultiMetricsEngine) RecordBidRecoveryResponseTime(publisher, profile string, responseTime time.Duration) { + for _, thisME := range *me { + thisME.RecordBidRecoveryResponseTime(publisher, profile, responseTime) + } +} diff --git a/modules/pubmatic/openwrap/metrics/config/multimetrics_test.go b/modules/pubmatic/openwrap/metrics/config/multimetrics_test.go index 2b206de8715..554ae4dc438 100644 --- a/modules/pubmatic/openwrap/metrics/config/multimetrics_test.go +++ b/modules/pubmatic/openwrap/metrics/config/multimetrics_test.go @@ -223,6 +223,8 @@ func TestRecordFunctionForMultiMetricsEngine(t *testing.T) { mockEngine.EXPECT().RecordOWServerPanic("endpoint", "methodName", "nodeName", "podName") mockEngine.EXPECT().RecordAmpVideoRequests("pubid", "profileid") mockEngine.EXPECT().RecordAmpVideoResponses("pubid", "profileid") + mockEngine.EXPECT().RecordBidRecoveryStatus(publisher, profile, true) + mockEngine.EXPECT().RecordBidRecoveryResponseTime(publisher, profile, time.Duration(200)) // create the multi-metric engine multiMetricEngine := MultiMetricsEngine{} @@ -291,4 +293,6 @@ func TestRecordFunctionForMultiMetricsEngine(t *testing.T) { multiMetricEngine.RecordOWServerPanic("endpoint", "methodName", "nodeName", "podName") multiMetricEngine.RecordAmpVideoRequests("pubid", "profileid") multiMetricEngine.RecordAmpVideoResponses("pubid", "profileid") + multiMetricEngine.RecordBidRecoveryStatus(publisher, profile, true) + multiMetricEngine.RecordBidRecoveryResponseTime(publisher, profile, time.Duration(200)) } diff --git a/modules/pubmatic/openwrap/metrics/metrics.go b/modules/pubmatic/openwrap/metrics/metrics.go index dfe45a8d500..6af13a88689 100644 --- a/modules/pubmatic/openwrap/metrics/metrics.go +++ b/modules/pubmatic/openwrap/metrics/metrics.go @@ -25,6 +25,8 @@ type MetricsEngine interface { RecordPublisherRequests(endpoint string, publisher string, platform string) RecordReqImpsWithContentCount(publisher, contentType string) RecordInjectTrackerErrorCount(adformat, publisher, partner string) + RecordBidRecoveryStatus(publisher, profile string, success bool) + RecordBidRecoveryResponseTime(publisher, profile string, responseTime time.Duration) // not-captured in openwrap module, dont provide enough insights RecordPBSAuctionRequestsStats() diff --git a/modules/pubmatic/openwrap/metrics/mock/mock.go b/modules/pubmatic/openwrap/metrics/mock/mock.go index b98fde7c783..d70dc6a196c 100644 --- a/modules/pubmatic/openwrap/metrics/mock/mock.go +++ b/modules/pubmatic/openwrap/metrics/mock/mock.go @@ -815,6 +815,30 @@ func (mr *MockMetricsEngineMockRecorder) RecordVideoInstlImpsStats(arg0, arg1 in return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordVideoInstlImpsStats", reflect.TypeOf((*MockMetricsEngine)(nil).RecordVideoInstlImpsStats), arg0, arg1) } +// RecordBidRecoveryStatus mocks base method. +func (m *MockMetricsEngine) RecordBidRecoveryStatus(arg0 string, arg1 string, arg2 bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordBidRecoveryStatus", arg0, arg1, arg2) +} + +// RecordBidRecoveryStatus indicates an expected call of RecordBidRecoveryStatus. +func (mr *MockMetricsEngineMockRecorder) RecordBidRecoveryStatus(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordBidRecoveryStatus", reflect.TypeOf((*MockMetricsEngine)(nil).RecordBidRecoveryStatus), arg0, arg1, arg2) +} + +// RecordBidRecoveryResponseTime mocks base method. +func (m *MockMetricsEngine) RecordBidRecoveryResponseTime(arg0 string, arg1 string, arg2 time.Duration) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordBidRecoveryResponseTime", arg0, arg1, arg2) +} + +// RecordBidRecoveryResponseTime indicates an expected call of RecordBidRecoveryStatus. +func (mr *MockMetricsEngineMockRecorder) RecordBidRecoveryResponseTime(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordBidRecoveryResponseTime", reflect.TypeOf((*MockMetricsEngine)(nil).RecordBidRecoveryResponseTime), arg0, arg1, arg2) +} + // Shutdown mocks base method. func (m *MockMetricsEngine) Shutdown() { m.ctrl.T.Helper() diff --git a/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go b/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go index 2117caabaff..055cdf0a4ee 100644 --- a/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go +++ b/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go @@ -34,6 +34,8 @@ type Metrics struct { pubNoBidResponseErrors *prometheus.CounterVec pubResponseTime *prometheus.HistogramVec pubImpsWithContent *prometheus.CounterVec + pubBidRecoveryStatus *prometheus.CounterVec + pubBidRecoveryTime *prometheus.HistogramVec // publisher-partner-platform level metrics pubPartnerPlatformRequests *prometheus.CounterVec @@ -360,6 +362,19 @@ func newMetrics(cfg *config.PrometheusMetrics, promRegistry *prometheus.Registry []string{pubIdLabel, profileIDLabel}, ) + metrics.pubBidRecoveryTime = newHistogramVec(cfg, promRegistry, + "bid_recovery_response_time", + "Total time taken by request for secondary auction in ms at publisher profile level.", + []string{pubIDLabel, profileIDLabel}, + []float64{100, 200, 300, 400}, + ) + + metrics.pubBidRecoveryStatus = newCounter(cfg, promRegistry, + "bid_recovery_response_status", + "Count bid recovery status for secondary auction", + []string{pubIDLabel, profileIDLabel, successLabel}, + ) + newSSHBMetrics(&metrics, cfg, promRegistry) return &metrics @@ -680,3 +695,18 @@ func (m *Metrics) RecordPrebidCacheRequestTime(success bool, length time.Duratio successLabel: strconv.FormatBool(success), }).Observe(float64(length.Milliseconds())) } + +func (m *Metrics) RecordBidRecoveryStatus(publisherID, profileID string, success bool) { + m.pubBidRecoveryStatus.With(prometheus.Labels{ + pubIDLabel: publisherID, + profileIDLabel: profileID, + successLabel: strconv.FormatBool(success), + }).Inc() +} + +func (m *Metrics) RecordBidRecoveryResponseTime(publisherID, profileID string, responseTime time.Duration) { + m.pubBidRecoveryTime.With(prometheus.Labels{ + pubIDLabel: publisherID, + profileIDLabel: profileID, + }).Observe(float64(responseTime.Milliseconds())) +} diff --git a/modules/pubmatic/openwrap/metrics/prometheus/prometheus_test.go b/modules/pubmatic/openwrap/metrics/prometheus/prometheus_test.go index faff7bb23dc..9872b7356a9 100644 --- a/modules/pubmatic/openwrap/metrics/prometheus/prometheus_test.go +++ b/modules/pubmatic/openwrap/metrics/prometheus/prometheus_test.go @@ -374,6 +374,30 @@ func TestRecordAdruleValidationFailure(t *testing.T) { }) } +func TestRecordBidRecoveryStatus(t *testing.T) { + m := createMetricsForTesting() + + m.RecordBidRecoveryStatus("5890", "123", true) + + expectedCount := float64(1) + assertCounterVecValue(t, "", "bid_recovery_response_status", m.pubBidRecoveryStatus, + expectedCount, prometheus.Labels{ + pubIDLabel: "5890", + profileIDLabel: "123", + successLabel: "true", + }) +} + +func TestRecordBidRecoveryResponseTime(t *testing.T) { + m := createMetricsForTesting() + + m.RecordBidRecoveryResponseTime("5890", "12345", time.Duration(70)*time.Millisecond) + m.RecordBidRecoveryResponseTime("5890", "12345", time.Duration(130)*time.Millisecond) + resultingHistogram := getHistogramFromHistogramVecByTwoKeys(m.pubBidRecoveryTime, + pubIDLabel, "5890", profileIDLabel, "12345") + assertHistogram(t, "bid_recovery_response_time", resultingHistogram, 2, 200) +} + func getHistogramFromHistogramVec(histogram *prometheus.HistogramVec, labelKey, labelValue string) dto.Histogram { var result dto.Histogram processMetrics(histogram, func(m dto.Metric) { diff --git a/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go b/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go index 94ba5931eaa..82599a54489 100644 --- a/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go +++ b/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go @@ -350,5 +350,8 @@ func (st *StatsTCP) RecordAdruleEnabled(pubId, profId string) func (st *StatsTCP) RecordAdruleValidationFailure(pubId, profId string) {} func (st *StatsTCP) RecordSignalDataStatus(pubid, profileid, signalType string) {} func (st *StatsTCP) RecordPrebidCacheRequestTime(success bool, length time.Duration) {} +func (st *StatsTCP) RecordBidRecoveryStatus(pubID string, profile string, success bool) {} +func (st *StatsTCP) RecordBidRecoveryResponseTime(pubID string, profile string, responseTime time.Duration) { +} func (st *StatsTCP) RecordPrebidAuctionBidResponse(publisher string, partnerName string, bidderCode string, adapterCode string) { } From c10317d4f10d4c3257566c519f09bf4ac5fc8fdf Mon Sep 17 00:00:00 2001 From: Saurabh Narkhede <108730956+pm-saurabh-narkhede@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:05:08 +0530 Subject: [PATCH 17/24] UOE-11149: Send Encoded SSPBurl in bid.Burl (#908) --- modules/pubmatic/openwrap/auctionresponsehook_test.go | 4 ++-- modules/pubmatic/openwrap/tracker/banner_test.go | 2 +- modules/pubmatic/openwrap/tracker/inject.go | 4 +++- modules/pubmatic/openwrap/tracker/inject_test.go | 10 +++++----- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/pubmatic/openwrap/auctionresponsehook_test.go b/modules/pubmatic/openwrap/auctionresponsehook_test.go index db94524cb85..0b3258e090b 100644 --- a/modules/pubmatic/openwrap/auctionresponsehook_test.go +++ b/modules/pubmatic/openwrap/auctionresponsehook_test.go @@ -1906,8 +1906,8 @@ func TestAuctionResponseHookForApplovinMax(t *testing.T) { ID: "456", ImpID: "789", Price: 1.0, - BURL: `https:?adv=&af=video&aps=0&au=&bc=pubmatic&bidid=456&di=-1&eg=1&en=1&ft=0&iid=&kgpv=&orig=&origbidid=456&pdvid=0&pid=0&plt=0&pn=pubmatic&psz=0x0&pubid=0&purl=&sl=1&slot=&ss=1&tgid=0&tst=0&owsspburl=http://example.com`, - Ext: json.RawMessage(`{"signaldata":"{\"id\":\"123\",\"seatbid\":[{\"bid\":[{\"id\":\"456\",\"impid\":\"789\",\"price\":1,\"burl\":\"https:?adv=\\u0026af=video\\u0026aps=0\\u0026au=\\u0026bc=pubmatic\\u0026bidid=456\\u0026di=-1\\u0026eg=1\\u0026en=1\\u0026ft=0\\u0026iid=\\u0026kgpv=\\u0026orig=\\u0026origbidid=456\\u0026pdvid=0\\u0026pid=0\\u0026plt=0\\u0026pn=pubmatic\\u0026psz=0x0\\u0026pubid=0\\u0026purl=\\u0026sl=1\\u0026slot=\\u0026ss=1\\u0026tgid=0\\u0026tst=0\\u0026owsspburl=http://example.com\",\"adm\":\"\\u003cVAST version=\\\"3.0\\\"\\u003e\\u003cAd id=\\\"601364\\\"\\u003e\\u003cInLine\\u003e\\u003cAdSystem\\u003e\\u003c![CDATA[Acudeo Compatible]]\\u003e\\u003c/AdSystem\\u003e\\u003cAdTitle\\u003e\\u003c![CDATA[VAST 2.0 Instream Test 1]]\\u003e\\u003c/AdTitle\\u003e\\u003cDescription\\u003e\\u003c![CDATA[VAST 2.0 Instream Test 1]]\\u003e\\u003c/Description\\u003e\\u003cImpression\\u003e\\u003c![CDATA[http://172.16.4.213/AdServer/AdDisplayTrackerServlet?operId=1\\u0026pubId=5890\\u0026siteId=47163\\u0026adId=1405268\\u0026adType=13\\u0026adServerId=243\\u0026kefact=70.000000\\u0026kaxefact=70.000000\\u0026kadNetFrequecy=0\\u0026kadwidth=0\\u0026kadheight=0\\u0026kadsizeid=97\\u0026kltstamp=1529929473\\u0026indirectAdId=0\\u0026adServerOptimizerId=2\\u0026ranreq=0.1\\u0026kpbmtpfact=100.000000\\u0026dcId=1\\u0026tldId=0\\u0026passback=0\\u0026svr=MADS1107\\u0026ekefact=Ad8wW91TCwCmdG0jlfjXn7Tyzh20hnTVx-m5DoNSep-RXGDr\\u0026ekaxefact=Ad8wWwRUCwAGir4Zzl1eF0bKiC-qrCV0D0yp_eE7YizB_BQk\\u0026ekpbmtpfact=Ad8wWxRUCwD7qgzwwPE2LnS5-Ou19uO5amJl1YT6-XVFvQ41\\u0026imprId=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026oid=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026crID=creative-1_1_2\\u0026ucrid=160175026529250297\\u0026campaignId=17050\\u0026creativeId=0\\u0026pctr=0.000000\\u0026wDSPByrId=511\\u0026wDspId=6\\u0026wbId=0\\u0026wrId=0\\u0026wAdvID=3170\\u0026isRTB=1\\u0026rtbId=EBCA079F-8D7C-45B8-B733-92951F670AA1\\u0026pmZoneId=zone1\\u0026pageURL=www.yahoo.com\\u0026lpu=ae.com]]\\u003e\\u003c/Impression\\u003e\\u003cImpression\\u003e\\u003c![CDATA[https://dsptracker.com/{PSPM}]]\\u003e\\u003c/Impression\\u003e\\u003cError\\u003e\\u003c![CDATA[http://172.16.4.213/track?operId=7\\u0026p=5890\\u0026s=47163\\u0026a=1405268\\u0026wa=243\\u0026ts=1529929473\\u0026wc=17050\\u0026crId=creative-1_1_2\\u0026ucrid=160175026529250297\\u0026impid=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026advertiser_id=3170\\u0026ecpm=70.000000\\u0026er=[ERRORCODE]]]\\u003e\\u003c/Error\\u003e\\u003cError\\u003e\\u003c![CDATA[https://Errortrack.com?p=1234\\u0026er=[ERRORCODE]]]\\u003e\\u003c/Error\\u003e\\u003cCreatives\\u003e\\u003cCreative AdID=\\\"601364\\\"\\u003e\\u003cLinear skipoffset=\\\"20%\\\"\\u003e\\u003cDuration\\u003e\\u003c![CDATA[00:00:04]]\\u003e\\u003c/Duration\\u003e\\u003cVideoClicks\\u003e\\u003cClickTracking\\u003e\\u003c![CDATA[http://172.16.4.213/track?operId=7\\u0026p=5890\\u0026s=47163\\u0026a=1405268\\u0026wa=243\\u0026ts=1529929473\\u0026wc=17050\\u0026crId=creative-1_1_2\\u0026ucrid=160175026529250297\\u0026impid=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026advertiser_id=3170\\u0026ecpm=70.000000\\u0026e=99]]\\u003e\\u003c/ClickTracking\\u003e\\u003cClickThrough\\u003e\\u003c![CDATA[https://www.sample.com]]\\u003e\\u003c/ClickThrough\\u003e\\u003c/VideoClicks\\u003e\\u003cMediaFiles\\u003e\\u003cMediaFile delivery=\\\"progressive\\\" type=\\\"video/mp4\\\" bitrate=\\\"500\\\" width=\\\"400\\\" height=\\\"300\\\" scalable=\\\"true\\\" maintainAspectRatio=\\\"true\\\"\\u003e\\u003c![CDATA[https://stagingnyc.pubmatic.com:8443/video/Shashank/mediaFileHost/media/mp4-sample-1.mp4]]\\u003e\\u003c/MediaFile\\u003e\\u003cMediaFile delivery=\\\"progressive\\\" type=\\\"video/mp4\\\" bitrate=\\\"500\\\" width=\\\"400\\\" height=\\\"300\\\" scalable=\\\"true\\\" maintainAspectRatio=\\\"true\\\"\\u003e\\u003c![CDATA[https://stagingnyc.pubmatic.com:8443/video/Shashank/mediaFileHost/media/mp4-sample-2.mp4]]\\u003e\\u003c/MediaFile\\u003e\\u003c/MediaFiles\\u003e\\u003c/Linear\\u003e\\u003c/Creative\\u003e\\u003c/Creatives\\u003e\\u003cPricing model=\\\"CPM\\\" currency=\\\"USD\\\"\\u003e\\u003c![CDATA[1]]\\u003e\\u003c/Pricing\\u003e\\u003c/InLine\\u003e\\u003c/Ad\\u003e\\u003c/VAST\\u003e\",\"ext\":{\"prebid\":{},\"crtype\":\"video\",\"netecpm\":1}}],\"seat\":\"pubmatic\"}],\"bidid\":\"456\",\"cur\":\"USD\",\"ext\":{\"matchedimpression\":{}}}"}`), + BURL: `https:?adv=&af=video&aps=0&au=&bc=pubmatic&bidid=456&di=-1&eg=1&en=1&ft=0&iid=&kgpv=&orig=&origbidid=456&pdvid=0&pid=0&plt=0&pn=pubmatic&psz=0x0&pubid=0&purl=&sl=1&slot=&ss=1&tgid=0&tst=0&owsspburl=http%3A%2F%2Fexample.com`, + Ext: json.RawMessage(`{"signaldata":"{\"id\":\"123\",\"seatbid\":[{\"bid\":[{\"id\":\"456\",\"impid\":\"789\",\"price\":1,\"burl\":\"https:?adv=\\u0026af=video\\u0026aps=0\\u0026au=\\u0026bc=pubmatic\\u0026bidid=456\\u0026di=-1\\u0026eg=1\\u0026en=1\\u0026ft=0\\u0026iid=\\u0026kgpv=\\u0026orig=\\u0026origbidid=456\\u0026pdvid=0\\u0026pid=0\\u0026plt=0\\u0026pn=pubmatic\\u0026psz=0x0\\u0026pubid=0\\u0026purl=\\u0026sl=1\\u0026slot=\\u0026ss=1\\u0026tgid=0\\u0026tst=0\\u0026owsspburl=http%3A%2F%2Fexample.com\",\"adm\":\"\\u003cVAST version=\\\"3.0\\\"\\u003e\\u003cAd id=\\\"601364\\\"\\u003e\\u003cInLine\\u003e\\u003cAdSystem\\u003e\\u003c![CDATA[Acudeo Compatible]]\\u003e\\u003c/AdSystem\\u003e\\u003cAdTitle\\u003e\\u003c![CDATA[VAST 2.0 Instream Test 1]]\\u003e\\u003c/AdTitle\\u003e\\u003cDescription\\u003e\\u003c![CDATA[VAST 2.0 Instream Test 1]]\\u003e\\u003c/Description\\u003e\\u003cImpression\\u003e\\u003c![CDATA[http://172.16.4.213/AdServer/AdDisplayTrackerServlet?operId=1\\u0026pubId=5890\\u0026siteId=47163\\u0026adId=1405268\\u0026adType=13\\u0026adServerId=243\\u0026kefact=70.000000\\u0026kaxefact=70.000000\\u0026kadNetFrequecy=0\\u0026kadwidth=0\\u0026kadheight=0\\u0026kadsizeid=97\\u0026kltstamp=1529929473\\u0026indirectAdId=0\\u0026adServerOptimizerId=2\\u0026ranreq=0.1\\u0026kpbmtpfact=100.000000\\u0026dcId=1\\u0026tldId=0\\u0026passback=0\\u0026svr=MADS1107\\u0026ekefact=Ad8wW91TCwCmdG0jlfjXn7Tyzh20hnTVx-m5DoNSep-RXGDr\\u0026ekaxefact=Ad8wWwRUCwAGir4Zzl1eF0bKiC-qrCV0D0yp_eE7YizB_BQk\\u0026ekpbmtpfact=Ad8wWxRUCwD7qgzwwPE2LnS5-Ou19uO5amJl1YT6-XVFvQ41\\u0026imprId=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026oid=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026crID=creative-1_1_2\\u0026ucrid=160175026529250297\\u0026campaignId=17050\\u0026creativeId=0\\u0026pctr=0.000000\\u0026wDSPByrId=511\\u0026wDspId=6\\u0026wbId=0\\u0026wrId=0\\u0026wAdvID=3170\\u0026isRTB=1\\u0026rtbId=EBCA079F-8D7C-45B8-B733-92951F670AA1\\u0026pmZoneId=zone1\\u0026pageURL=www.yahoo.com\\u0026lpu=ae.com]]\\u003e\\u003c/Impression\\u003e\\u003cImpression\\u003e\\u003c![CDATA[https://dsptracker.com/{PSPM}]]\\u003e\\u003c/Impression\\u003e\\u003cError\\u003e\\u003c![CDATA[http://172.16.4.213/track?operId=7\\u0026p=5890\\u0026s=47163\\u0026a=1405268\\u0026wa=243\\u0026ts=1529929473\\u0026wc=17050\\u0026crId=creative-1_1_2\\u0026ucrid=160175026529250297\\u0026impid=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026advertiser_id=3170\\u0026ecpm=70.000000\\u0026er=[ERRORCODE]]]\\u003e\\u003c/Error\\u003e\\u003cError\\u003e\\u003c![CDATA[https://Errortrack.com?p=1234\\u0026er=[ERRORCODE]]]\\u003e\\u003c/Error\\u003e\\u003cCreatives\\u003e\\u003cCreative AdID=\\\"601364\\\"\\u003e\\u003cLinear skipoffset=\\\"20%\\\"\\u003e\\u003cDuration\\u003e\\u003c![CDATA[00:00:04]]\\u003e\\u003c/Duration\\u003e\\u003cVideoClicks\\u003e\\u003cClickTracking\\u003e\\u003c![CDATA[http://172.16.4.213/track?operId=7\\u0026p=5890\\u0026s=47163\\u0026a=1405268\\u0026wa=243\\u0026ts=1529929473\\u0026wc=17050\\u0026crId=creative-1_1_2\\u0026ucrid=160175026529250297\\u0026impid=48F73E1A-7F23-443D-A53C-30EE6BBF5F7F\\u0026advertiser_id=3170\\u0026ecpm=70.000000\\u0026e=99]]\\u003e\\u003c/ClickTracking\\u003e\\u003cClickThrough\\u003e\\u003c![CDATA[https://www.sample.com]]\\u003e\\u003c/ClickThrough\\u003e\\u003c/VideoClicks\\u003e\\u003cMediaFiles\\u003e\\u003cMediaFile delivery=\\\"progressive\\\" type=\\\"video/mp4\\\" bitrate=\\\"500\\\" width=\\\"400\\\" height=\\\"300\\\" scalable=\\\"true\\\" maintainAspectRatio=\\\"true\\\"\\u003e\\u003c![CDATA[https://stagingnyc.pubmatic.com:8443/video/Shashank/mediaFileHost/media/mp4-sample-1.mp4]]\\u003e\\u003c/MediaFile\\u003e\\u003cMediaFile delivery=\\\"progressive\\\" type=\\\"video/mp4\\\" bitrate=\\\"500\\\" width=\\\"400\\\" height=\\\"300\\\" scalable=\\\"true\\\" maintainAspectRatio=\\\"true\\\"\\u003e\\u003c![CDATA[https://stagingnyc.pubmatic.com:8443/video/Shashank/mediaFileHost/media/mp4-sample-2.mp4]]\\u003e\\u003c/MediaFile\\u003e\\u003c/MediaFiles\\u003e\\u003c/Linear\\u003e\\u003c/Creative\\u003e\\u003c/Creatives\\u003e\\u003cPricing model=\\\"CPM\\\" currency=\\\"USD\\\"\\u003e\\u003c![CDATA[1]]\\u003e\\u003c/Pricing\\u003e\\u003c/InLine\\u003e\\u003c/Ad\\u003e\\u003c/VAST\\u003e\",\"ext\":{\"prebid\":{},\"crtype\":\"video\",\"netecpm\":1}}],\"seat\":\"pubmatic\"}],\"bidid\":\"456\",\"cur\":\"USD\",\"ext\":{\"matchedimpression\":{}}}"}`), }, }, }, diff --git a/modules/pubmatic/openwrap/tracker/banner_test.go b/modules/pubmatic/openwrap/tracker/banner_test.go index c72f6c6b4e0..0b83ec221e9 100644 --- a/modules/pubmatic/openwrap/tracker/banner_test.go +++ b/modules/pubmatic/openwrap/tracker/banner_test.go @@ -40,7 +40,7 @@ func Test_injectBannerTracker(t *testing.T) { seat: "pubmatic", }, wantAdm: `
`, - wantBurl: `sample.com/track?tid=1234&owsspburl=http://burl.com`, + wantBurl: `sample.com/track?tid=1234&owsspburl=http%3A%2F%2Fburl.com`, }, { name: "app_platform", diff --git a/modules/pubmatic/openwrap/tracker/inject.go b/modules/pubmatic/openwrap/tracker/inject.go index 06cb70c25e3..e3dd6f6d72f 100644 --- a/modules/pubmatic/openwrap/tracker/inject.go +++ b/modules/pubmatic/openwrap/tracker/inject.go @@ -3,6 +3,7 @@ package tracker import ( "errors" "fmt" + "net/url" "strings" "golang.org/x/exp/slices" @@ -91,5 +92,6 @@ func getBURL(burl, trackerURL string) string { return trackerURL } - return trackerURL + "&" + models.OwSspBurl + "=" + burl + escapedBurl := url.QueryEscape(burl) + return trackerURL + "&" + models.OwSspBurl + "=" + escapedBurl } diff --git a/modules/pubmatic/openwrap/tracker/inject_test.go b/modules/pubmatic/openwrap/tracker/inject_test.go index 0eed8b3e37a..483414340ef 100644 --- a/modules/pubmatic/openwrap/tracker/inject_test.go +++ b/modules/pubmatic/openwrap/tracker/inject_test.go @@ -548,7 +548,7 @@ func TestInjectTrackers(t *testing.T) { Bid: []openrtb2.Bid{ { ID: "12345", - BURL: `Tracking URL&owsspburl=http://burl.com`, + BURL: `Tracking URL&owsspburl=http%3A%2F%2Fburl.com`, AdM: `
`, }, }, @@ -591,7 +591,7 @@ func TestInjectTrackers(t *testing.T) { Bid: []openrtb2.Bid{ { ID: "12345", - BURL: `Tracking URL&owsspburl=http://burl.com`, + BURL: `Tracking URL&owsspburl=http%3A%2F%2Fburl.com`, AdM: ``, }, }, @@ -643,7 +643,7 @@ func TestInjectTrackers(t *testing.T) { { ID: "12345", ImpID: "imp123", - BURL: `Tracking URL&owsspburl=http://burl.com`, + BURL: `Tracking URL&owsspburl=http%3A%2F%2Fburl.com`, AdM: `{"assets":[{"id":0,"img":{"type":3,"url":"//sample.com/AdTag/native/728x90.png","w":728,"h":90}},{"id":1,"data":{"type":1,"value":"Sponsored By PubMatic"}},{"id":2,"img":{"type":1,"url":"//sample.com/AdTag/native/728x90.png","w":728,"h":90}},{"id":3,"title":{"text":"Native Test Title"}},{"id":4,"data":{"type":2,"value":"Sponsored By PubMatic"}}],"link":{"url":"//www.sample.com","clicktrackers":["http://sampletracker.com/AdTag/9bde02d0-6017-11e4-9df7-005056967c35"],"fallback":"http://www.sample.com"},"imptrackers":["http://sampletracker.com/AdTag/9bde02d0-6017-11e4-9df7-005056967c35"],"jstracker":"\u003cscript src='\\/\\/sample.com\\/AdTag\\/native\\/tempReseponse.js'\u003e\u003cscript src='\\/\\/sample.com\\/AdTag\\/native\\/tempReseponse.js'\u003e","eventtrackers":[{"event":1,"method":1,"url":"http://sample.com/AdServer/AdDisplayTrackerServlet"}]}`, }, }, @@ -1138,10 +1138,10 @@ func Test_getBurlAppLovinMax(t *testing.T) { { name: "valid_burl_and_tracker_url", args: args{ - burl: `sampleBurl.com`, + burl: `https://abc.xyz.com/AdServer/AdDisplayTrackerServlet?operId=1&pubId=161527&siteId=991727&adId=4695996&imprId=B430AE6F-4768-41D0-BC55-8CF9D5DD4DA6&cksum=41C0F6460C2ACF7F&adType=10&adServerId=243&kefact=0.095500&kaxefact=0.095500&kadNetFrequecy=0&kadwidth=300&kadheight=250&kadsizeid=9&kltstamp=1721827593&indirectAdId=0`, TrackerURL: `sampleTracker.com?id=123`, }, - want: `sampleTracker.com?id=123&owsspburl=sampleBurl.com`, + want: `sampleTracker.com?id=123&owsspburl=https%3A%2F%2Fabc.xyz.com%2FAdServer%2FAdDisplayTrackerServlet%3FoperId%3D1%26pubId%3D161527%26siteId%3D991727%26adId%3D4695996%26imprId%3DB430AE6F-4768-41D0-BC55-8CF9D5DD4DA6%26cksum%3D41C0F6460C2ACF7F%26adType%3D10%26adServerId%3D243%26kefact%3D0.095500%26kaxefact%3D0.095500%26kadNetFrequecy%3D0%26kadwidth%3D300%26kadheight%3D250%26kadsizeid%3D9%26kltstamp%3D1721827593%26indirectAdId%3D0`, }, } for _, tt := range tests { From 69030ce63a57274b11614f8d1ca2c7b0bcdffc12 Mon Sep 17 00:00:00 2001 From: Saurabh Narkhede <108730956+pm-saurabh-narkhede@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:33:12 +0530 Subject: [PATCH 18/24] UOE-11149: Fix Tests-Send Encoded SSPBurl in bid.Burl (#909) --- modules/pubmatic/openwrap/tracker/native_test.go | 2 +- modules/pubmatic/openwrap/tracker/video_test.go | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/pubmatic/openwrap/tracker/native_test.go b/modules/pubmatic/openwrap/tracker/native_test.go index 3c8a030d445..5b1d1ef1b37 100644 --- a/modules/pubmatic/openwrap/tracker/native_test.go +++ b/modules/pubmatic/openwrap/tracker/native_test.go @@ -36,7 +36,7 @@ func Test_injectNativeCreativeTrackers(t *testing.T) { }, endpoint: models.EndpointAppLovinMax, }, - wantBurl: `t.pubmatic.com/track?tid=1234&owsspburl=http://burl.com`, + wantBurl: `t.pubmatic.com/track?tid=1234&owsspburl=http%3A%2F%2Fburl.com`, wantAdm: `
`, wantErr: false, }, diff --git a/modules/pubmatic/openwrap/tracker/video_test.go b/modules/pubmatic/openwrap/tracker/video_test.go index 3995b480092..b8629f1afc9 100644 --- a/modules/pubmatic/openwrap/tracker/video_test.go +++ b/modules/pubmatic/openwrap/tracker/video_test.go @@ -311,7 +311,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracking URL&owsspburl=https://burl.com", + wantBurl: "Tracking URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ``, wantErr: false, }, @@ -334,7 +334,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracker URL&owsspburl=https://burl.com", + wantBurl: "Tracker URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ``, wantErr: false, }, @@ -357,7 +357,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracker URL&owsspburl=https://burl.com", + wantBurl: "Tracker URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ``, wantErr: false, }, @@ -380,7 +380,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracker URL&owsspburl=https://burl.com", + wantBurl: "Tracker URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ``, wantErr: false, }, @@ -403,7 +403,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracker URL&owsspburl=https://burl.com", + wantBurl: "Tracker URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ``, wantErr: false, }, @@ -426,7 +426,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracker URL&owsspburl=https://burl.com", + wantBurl: "Tracker URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ``, wantErr: false, }, @@ -448,7 +448,7 @@ func TestInjectVideoCreativeTrackers(t *testing.T) { Endpoint: models.EndpointAppLovinMax, }, }, - wantBurl: "Tracker URL&owsspburl=https://burl.com", + wantBurl: "Tracker URL&owsspburl=https%3A%2F%2Fburl.com", wantAdm: ` `, wantErr: false, }, From 8df3a61333471b8ba7f8fe7e3c1cf47e35242c72 Mon Sep 17 00:00:00 2001 From: supriya-patil Date: Thu, 19 Sep 2024 17:58:01 +0530 Subject: [PATCH 19/24] OTT-1990: select Valid Inline and banner creatives in case of VAST unwrap is enabled for given profile --- .../openwrap/hook_raw_bidder_response.go | 1 + .../openwrap/hook_raw_bidder_response_test.go | 105 ++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response.go b/modules/pubmatic/openwrap/hook_raw_bidder_response.go index c7674f0c436..49b0a5aa114 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response.go @@ -39,6 +39,7 @@ func (m OpenWrap) handleRawBidderResponseHook( // send bids for unwrap for _, bid := range payload.BidderResponse.Bids { if !isEligibleForUnwrap(bid) { + unwrappedBids = append(unwrappedBids, bid) continue } unwrappedBidsCnt++ diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go index 22bbf71b498..2d8cec5cf32 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go @@ -3,6 +3,7 @@ package openwrap import ( "fmt" "net/http" + "reflect" "testing" unWrapCfg "git.pubmatic.com/vastunwrap/config" @@ -41,6 +42,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { setup func() wantSeatNonBid openrtb_ext.NonBidCollection mockHandler http.HandlerFunc + wantBids []*adapters.TypedBid }{ { name: "Empty Request Context", @@ -166,6 +168,20 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "1") mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) }, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: invalidVastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, }, { name: "Set Vast Unwrapper to true in request context with type video", @@ -217,6 +233,20 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()) }, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: inlineXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, }, { name: "Set Vast Unwrapper to true in request context for multiple bids with type video", @@ -279,6 +309,31 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()).Times(2) mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()).Times(2) }, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: inlineXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: inlineXMLAdM, + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "video", + }}, }, { name: "Set Vast Unwrapper to true in request context for multiple bids with different type", @@ -341,6 +396,31 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "0", gomock.Any()) }, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: inlineXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }}, }, { name: "Set Vast Unwrapper to true in request context with type video and source owsdk", @@ -392,6 +472,20 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "1", gomock.Any()) }, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, }, { name: "bid with InvalidVAST should be discarded and should be present in seatNonBid", @@ -438,6 +532,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", models.UnwrapInvalidVASTStatus) mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) }, + wantBids: []*adapters.TypedBid{}, wantSeatNonBid: func() openrtb_ext.NonBidCollection { seatNonBid := openrtb_ext.NonBidCollection{} seatNonBid.AddBid(openrtb_ext.NonBid{ @@ -503,6 +598,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", models.UnwrapEmptyVASTStatus) mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) }, + wantBids: []*adapters.TypedBid{}, wantSeatNonBid: func() openrtb_ext.NonBidCollection { seatNonBid := openrtb_ext.NonBidCollection{} seatNonBid.AddBid(openrtb_ext.NonBid{ @@ -536,6 +632,15 @@ func TestHandleRawBidderResponseHook(t *testing.T) { if tt.args.moduleInvocationCtx.ModuleContext != nil && tt.args.isAdmUpdated { assert.Equal(t, inlineXMLAdM, tt.args.payload.BidderResponse.Bids[0].Bid.AdM, "AdM is not updated correctly after executing RawBidderResponse hook.") } + for _, mut := range hookResult.ChangeSet.Mutations() { + newPayload, err := mut.Apply(tt.args.payload) + assert.NoError(t, err) + tt.args.payload = newPayload + } + if tt.wantBids != nil { + reflect.DeepEqual(tt.args.payload.BidderResponse.Bids, tt.wantBids) + } + assert.Equal(t, tt.wantSeatNonBid, hookResult.SeatNonBid, "mismatched seatNonBids") }) } From c4096aca8a651e59a3ad55a3b996bb12a096b711 Mon Sep 17 00:00:00 2001 From: supriya-patil Date: Thu, 19 Sep 2024 23:22:58 +0530 Subject: [PATCH 20/24] OTT-1990: Added unit test case for non video type bids --- .../openwrap/hook_raw_bidder_response_test.go | 206 ++++++++++++++++-- 1 file changed, 185 insertions(+), 21 deletions(-) diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go index 2d8cec5cf32..046ef485845 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go @@ -3,7 +3,6 @@ package openwrap import ( "fmt" "net/http" - "reflect" "testing" unWrapCfg "git.pubmatic.com/vastunwrap/config" @@ -45,14 +44,14 @@ func TestHandleRawBidderResponseHook(t *testing.T) { wantBids []*adapters.TypedBid }{ { - name: "Empty Request Context", + name: "Empty_Request_Context", args: args{ module: OpenWrap{}, }, wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{DebugMessages: []string{"error: request-ctx not found in handleRawBidderResponseHook()"}}, }, { - name: "Set Vast Unwrapper to false in request context with type video", + name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video", args: args{ module: OpenWrap{ cfg: config.Config{VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ @@ -82,7 +81,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, }, { - name: "Set Vast Unwrapper to false in request context with type video, stats enabled true", + name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video,_stats_enabled_true", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -124,7 +123,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set Vast Unwrapper to true in request context with invalid vast xml", + name: "Set_Vast_Unwrapper_to_true_in_request_context_with_invalid_vast_xml", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -184,7 +183,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set Vast Unwrapper to true in request context with type video", + name: "Set_Vast_Unwrapper_to_true_in_request_context_with_type_video", mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Add("unwrap-status", "0") w.Header().Add("unwrap-count", "1") @@ -249,7 +248,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set Vast Unwrapper to true in request context for multiple bids with type video", + name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_type_video", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -312,11 +311,11 @@ func TestHandleRawBidderResponseHook(t *testing.T) { wantBids: []*adapters.TypedBid{ { Bid: &openrtb2.Bid{ - ID: "Bid-123", + ID: "Bid-456", ImpID: fmt.Sprintf("div-adunit-%d", 123), Price: 2.1, AdM: inlineXMLAdM, - CrID: "Cr-234", + CrID: "Cr-789", W: 100, H: 50, }, @@ -324,19 +323,20 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, { Bid: &openrtb2.Bid{ - ID: "Bid-456", + ID: "Bid-123", ImpID: fmt.Sprintf("div-adunit-%d", 123), Price: 2.1, AdM: inlineXMLAdM, - CrID: "Cr-789", + CrID: "Cr-234", W: 100, H: 50, }, BidType: "video", - }}, + }, + }, }, { - name: "Set Vast Unwrapper to true in request context for multiple bids with different type", + name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_different_type", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -397,6 +397,18 @@ func TestHandleRawBidderResponseHook(t *testing.T) { mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "0", gomock.Any()) }, wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }, { Bid: &openrtb2.Bid{ ID: "Bid-123", @@ -409,21 +421,98 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, BidType: "video", }, + }, + }, + { + name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_native_and_video_type", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{ + VASTUnwrapPercent: 50, + }, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is native creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "native", + }}, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, + isAdmUpdated: true, + }, + mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Add("unwrap-status", "0") + w.Header().Add("unwrap-count", "0") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(inlineXMLAdM)) + }), + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + setup: func() { + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "0") + mockMetricsEngine.EXPECT().RecordUnwrapWrapperCount("5890", "pubmatic", "0") + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) + mockMetricsEngine.EXPECT().RecordUnwrapRespTime("5890", "0", gomock.Any()) + }, + wantBids: []*adapters.TypedBid{ { Bid: &openrtb2.Bid{ ID: "Bid-456", ImpID: fmt.Sprintf("div-adunit-%d", 123), Price: 2.1, - AdM: "This is banner creative", + AdM: "This is native creative", CrID: "Cr-789", W: 100, H: 50, }, - BidType: "banner", - }}, + BidType: "native", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: inlineXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, }, { - name: "Set Vast Unwrapper to true in request context with type video and source owsdk", + name: "Set_Vast_Unwrapper_to_true_in_request_context_with_type_video_and_source_owsdk", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -478,7 +567,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { ID: "Bid-123", ImpID: fmt.Sprintf("div-adunit-%d", 123), Price: 2.1, - AdM: vastXMLAdM, + AdM: inlineXMLAdM, CrID: "Cr-234", W: 100, H: 50, @@ -488,7 +577,82 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "bid with InvalidVAST should be discarded and should be present in seatNonBid", + name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_nonvideo_type", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{ + VASTUnwrapPercent: 50, + }, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "banner", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is native creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "native", + }}, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, + } + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "banner", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is native creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "native", + }, + }, + }, + { + name: "bid_with_InvalidVAST_should_be_discarded_and_should_be_present_in_seatNonBid", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -554,7 +718,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }(), }, { - name: "bid with EmptyVAST should be discarded and should be present in seatNonBid", + name: "bid_with_EmptyVAST_should_be_discarded_and_should_be_present_in_seatNonBid", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -638,7 +802,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { tt.args.payload = newPayload } if tt.wantBids != nil { - reflect.DeepEqual(tt.args.payload.BidderResponse.Bids, tt.wantBids) + assert.Equal(t, tt.wantBids, tt.args.payload.BidderResponse.Bids, "Mismatched response bids") } assert.Equal(t, tt.wantSeatNonBid, hookResult.SeatNonBid, "mismatched seatNonBids") From 8ac160d5f513a3cfc977835d210cc552823877f3 Mon Sep 17 00:00:00 2001 From: supriya-patil Date: Fri, 20 Sep 2024 15:04:46 +0530 Subject: [PATCH 21/24] Addressed Review Comments --- .../openwrap/hook_raw_bidder_response.go | 2 + .../openwrap/hook_raw_bidder_response_test.go | 307 +++++++++++++++++- 2 files changed, 307 insertions(+), 2 deletions(-) diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response.go b/modules/pubmatic/openwrap/hook_raw_bidder_response.go index 49b0a5aa114..634afd29e2e 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response.go @@ -40,6 +40,8 @@ func (m OpenWrap) handleRawBidderResponseHook( for _, bid := range payload.BidderResponse.Bids { if !isEligibleForUnwrap(bid) { unwrappedBids = append(unwrappedBids, bid) + result.DebugMessages = append(result.DebugMessages, + fmt.Sprintf("For pubid:[%d] VastUnwrapEnabled: [%v]", vastRequestContext.PubID, vastRequestContext.VastUnwrapEnabled)) continue } unwrappedBidsCnt++ diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go index 046ef485845..033406ff0c7 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go @@ -253,7 +253,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { module: OpenWrap{ cfg: config.Config{ Features: config.FeatureToggle{ - VASTUnwrapPercent: 50, + VASTUnwrapPercent: 100, }, VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ MaxWrapperSupport: 5, @@ -622,7 +622,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { Bidder: "pubmatic", }, moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, - } + }, wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, wantBids: []*adapters.TypedBid{ { @@ -783,6 +783,309 @@ func TestHandleRawBidderResponseHook(t *testing.T) { return seatNonBid }(), }, + { + name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{}, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }}}, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: false}}}, + }, + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, + }, + { + name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video_and_banner", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{}, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }}, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: false}}}, + }, + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: vastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }, + }, + }, + { + name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_banner", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{}, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }}, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: false}}}, + }, + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }, + }, + }, + { + name: "Set_Vast_Unwrapper_to_true_in_request_context_with_type_banner", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{}, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }}, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, + }, + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }, + }, + }, + { + name: "Set_Vast_Unwrapper_to_true_in_request_context_with_invalid_vast_xml_and_banner_creative", + args: args{ + module: OpenWrap{ + cfg: config.Config{ + Features: config.FeatureToggle{ + VASTUnwrapPercent: 50, + }, + VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ + MaxWrapperSupport: 5, + StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, + APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, + }}, + metricEngine: mockMetricsEngine, + }, + payload: hookstage.RawBidderResponsePayload{ + BidderResponse: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: invalidVastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }, + }, + }, + Bidder: "pubmatic", + }, + moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: true}}}, + }, + mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Add("unwrap-status", "1") + w.WriteHeader(http.StatusNoContent) + }), + wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, + setup: func() { + mockMetricsEngine.EXPECT().RecordUnwrapRequestStatus("5890", "pubmatic", "1") + mockMetricsEngine.EXPECT().RecordUnwrapRequestTime("5890", "pubmatic", gomock.Any()) + }, + wantBids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "Bid-456", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: "This is banner creative", + CrID: "Cr-789", + W: 100, + H: 50, + }, + BidType: "banner", + }, + { + Bid: &openrtb2.Bid{ + ID: "Bid-123", + ImpID: fmt.Sprintf("div-adunit-%d", 123), + Price: 2.1, + AdM: invalidVastXMLAdM, + CrID: "Cr-234", + W: 100, + H: 50, + }, + BidType: "video", + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 2f849fcaf0aa441bf28da08161f6cc28b1655119 Mon Sep 17 00:00:00 2001 From: "dhruv.sonone" Date: Fri, 20 Sep 2024 15:21:00 +0530 Subject: [PATCH 22/24] Using ElementsMatch for assertion --- modules/pubmatic/openwrap/hook_raw_bidder_response_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go index 033406ff0c7..9bcefdebc8b 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go @@ -1105,7 +1105,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { tt.args.payload = newPayload } if tt.wantBids != nil { - assert.Equal(t, tt.wantBids, tt.args.payload.BidderResponse.Bids, "Mismatched response bids") + assert.ElementsMatch(t, tt.wantBids, tt.args.payload.BidderResponse.Bids, "Mismatched response bids") } assert.Equal(t, tt.wantSeatNonBid, hookResult.SeatNonBid, "mismatched seatNonBids") From 8140464345946ba59f7d9ab43fc03071e407c4b1 Mon Sep 17 00:00:00 2001 From: supriya-patil Date: Sat, 21 Sep 2024 14:21:33 +0530 Subject: [PATCH 23/24] Refactor test cases for handling VASTUnwrap configuration --- .../openwrap/hook_raw_bidder_response_test.go | 68 ++++--------------- 1 file changed, 13 insertions(+), 55 deletions(-) diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go index 9bcefdebc8b..421dd4f6285 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response_test.go @@ -51,7 +51,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{DebugMessages: []string{"error: request-ctx not found in handleRawBidderResponseHook()"}}, }, { - name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video", + name: "VASTUnwrap_Disabled_Video_Bids", args: args{ module: OpenWrap{ cfg: config.Config{VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ @@ -81,49 +81,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, }, { - name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video,_stats_enabled_true", - args: args{ - module: OpenWrap{ - cfg: config.Config{ - Features: config.FeatureToggle{}, - VastUnwrapCfg: unWrapCfg.VastUnWrapCfg{ - MaxWrapperSupport: 5, - StatConfig: unWrapCfg.StatConfig{Endpoint: "http://10.172.141.13:8080", PublishInterval: 1}, - APPConfig: unWrapCfg.AppConfig{UnwrapDefaultTimeout: 1500}, - }}, - metricEngine: mockMetricsEngine, - }, - payload: hookstage.RawBidderResponsePayload{ - BidderResponse: &adapters.BidderResponse{ - Bids: []*adapters.TypedBid{ - { - Bid: &openrtb2.Bid{ - ID: "Bid-123", - ImpID: fmt.Sprintf("div-adunit-%d", 123), - Price: 2.1, - AdM: vastXMLAdM, - CrID: "Cr-234", - W: 100, - H: 50, - }, - BidType: "video", - }}}, - Bidder: "pubmatic", - }, - moduleInvocationCtx: hookstage.ModuleInvocationContext{AccountID: "5890", ModuleContext: hookstage.ModuleContext{models.RequestContext: models.RequestCtx{VastUnwrapEnabled: false}}}, - }, - mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.Header().Add("unwrap-status", "0") - w.Header().Add("unwrap-count", "1") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(vastXMLAdM)) - }), - wantResult: hookstage.HookResult[hookstage.RawBidderResponsePayload]{Reject: false}, - setup: func() { - }, - }, - { - name: "Set_Vast_Unwrapper_to_true_in_request_context_with_invalid_vast_xml", + name: "VASTUnwrap_Enabled_Single_Video_Bid_Invalid_Vast_xml", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -183,7 +141,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_with_type_video", + name: "VASTUnwrap_Enabled_Single_Video_Bid", mockHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Add("unwrap-status", "0") w.Header().Add("unwrap-count", "1") @@ -248,7 +206,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_type_video", + name: "VASTUnwrap_Enabled_Multiple_Video_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -336,7 +294,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_different_type", + name: "VASTUnwrap_Enabled_Video_and_Banner_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -424,7 +382,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_native_and_video_type", + name: "VASTUnwrap_Enabled_Video_and_Native_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -512,7 +470,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_with_type_video_and_source_owsdk", + name: "VASTUnwrap_Enabled_Single_Video_bid_and_source_owsdk", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -577,7 +535,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_for_multiple_bids_with_nonvideo_type", + name: "VASTUnwrap_Enabled_Native_and_Banner_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -784,7 +742,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }(), }, { - name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video", + name: "VASTUnwrap_Disabled_Video_Bids_Valid_XML", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -832,7 +790,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_video_and_banner", + name: "VASTUnwrap_Disabled_Video_and_Banner_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -905,7 +863,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_false_in_request_context_with_type_banner", + name: "VASTUnwrap_Disabled_Banner_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -954,7 +912,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_with_type_banner", + name: "VASTUnwrap_Enabled_Banner_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ @@ -1003,7 +961,7 @@ func TestHandleRawBidderResponseHook(t *testing.T) { }, }, { - name: "Set_Vast_Unwrapper_to_true_in_request_context_with_invalid_vast_xml_and_banner_creative", + name: "VASTUnwrap_Enabled_Invalid_Video_and_Banner_Bids", args: args{ module: OpenWrap{ cfg: config.Config{ From 175b4cfe37d86d1028bc1077cdb737ee4ae20449 Mon Sep 17 00:00:00 2001 From: supriya-patil Date: Tue, 24 Sep 2024 17:49:59 +0530 Subject: [PATCH 24/24] OTT-1990:improve debug messages --- modules/pubmatic/openwrap/hook_raw_bidder_response.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/pubmatic/openwrap/hook_raw_bidder_response.go b/modules/pubmatic/openwrap/hook_raw_bidder_response.go index 634afd29e2e..a97f80a5af4 100644 --- a/modules/pubmatic/openwrap/hook_raw_bidder_response.go +++ b/modules/pubmatic/openwrap/hook_raw_bidder_response.go @@ -35,13 +35,12 @@ func (m OpenWrap) handleRawBidderResponseHook( unwrappedBidsChan := make(chan BidUnwrapInfo, len(payload.BidderResponse.Bids)) defer close(unwrappedBidsChan) - unwrappedBidsCnt := 0 + unwrappedBidsCnt, unwrappedSuccessBidCnt := 0, 0 + totalBidCnt := len(payload.BidderResponse.Bids) // send bids for unwrap for _, bid := range payload.BidderResponse.Bids { if !isEligibleForUnwrap(bid) { unwrappedBids = append(unwrappedBids, bid) - result.DebugMessages = append(result.DebugMessages, - fmt.Sprintf("For pubid:[%d] VastUnwrapEnabled: [%v]", vastRequestContext.PubID, vastRequestContext.VastUnwrapEnabled)) continue } unwrappedBidsCnt++ @@ -55,6 +54,7 @@ func (m OpenWrap) handleRawBidderResponseHook( for i := 0; i < unwrappedBidsCnt; i++ { unwrappedBid := <-unwrappedBidsChan if !rejectBid(unwrappedBid.unwrapStatus) { + unwrappedSuccessBidCnt++ unwrappedBids = append(unwrappedBids, unwrappedBid.bid) continue } @@ -75,8 +75,7 @@ func (m OpenWrap) handleRawBidderResponseHook( result.ChangeSet = changeSet result.SeatNonBid = seatNonBid result.DebugMessages = append(result.DebugMessages, - fmt.Sprintf("For pubid:[%d] VastUnwrapEnabled: [%v]", vastRequestContext.PubID, vastRequestContext.VastUnwrapEnabled)) - + fmt.Sprintf("For pubid:[%d] VastUnwrapEnabled: [%v] Total Input Bids: [%d] Total Bids sent for unwrapping: [%d] Total Unwrap Success: [%d]", vastRequestContext.PubID, vastRequestContext.VastUnwrapEnabled, totalBidCnt, unwrappedBidsCnt, unwrappedSuccessBidCnt)) return result, nil }