From 7ad739b0a2431f4c930307ec55b8c66dec3e62b0 Mon Sep 17 00:00:00 2001 From: Ankit-Pinge <128145896+Ankit-Pinge@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:53:22 +0530 Subject: [PATCH 1/2] OTT-1726: analytics throttling based on feature and vault configuration (#778) Co-authored-by: Viral Vala --- Makefile | 2 +- analytics/pubmatic/logger.go | 2 +- analytics/pubmatic/logger_test.go | 22 ++ analytics/pubmatic/mhttp/mock/mock.go | 51 +-- analytics/pubmatic/pubmatic.go | 5 + analytics/pubmatic/pubmatic_test.go | 32 ++ exchange/events.go | 10 +- exchange/events_test.go | 8 +- exchange/utils_ow_test.go | 236 ++++++------ .../openwrap/auctionresponsehook_test.go | 14 +- .../pubmatic/openwrap/beforevalidationhook.go | 5 +- .../openwrap/beforevalidationhook_test.go | 40 +- modules/pubmatic/openwrap/cache/mock/mock.go | 49 +-- modules/pubmatic/openwrap/config/config.go | 6 +- .../pubmatic/openwrap/database/mock/mock.go | 45 +-- .../openwrap/database/mock_driver/mock.go | 63 ++-- .../endpoints/legacy/openrtb/v25/video.go | 6 +- modules/pubmatic/openwrap/entrypointhook.go | 2 + .../pubmatic/openwrap/entrypointhook_test.go | 38 +- .../config/{metrics.go => multimetrics.go} | 7 + .../{metrics_test.go => multimetrics_test.go} | 2 + modules/pubmatic/openwrap/metrics/metrics.go | 1 + .../pubmatic/openwrap/metrics/mock/mock.go | 168 +++++---- .../openwrap/metrics/prometheus/prometheus.go | 44 ++- .../openwrap/metrics/stats/tcp_stats.go | 1 + modules/pubmatic/openwrap/models/constants.go | 28 +- modules/pubmatic/openwrap/models/openwrap.go | 2 + modules/pubmatic/openwrap/openwrap.go | 12 +- modules/pubmatic/openwrap/openwrap_sshb.go | 2 +- .../publisherfeature/analyticsthrottle.go | 173 +++++++++ .../analyticsthrottle_test.go | 352 ++++++++++++++++++ .../openwrap/publisherfeature/feature.go | 1 + .../openwrap/publisherfeature/mock/mock.go | 40 +- .../openwrap/publisherfeature/reloader.go | 18 +- .../publisherfeature/reloader_test.go | 15 +- modules/pubmatic/openwrap/targeting.go | 2 +- modules/pubmatic/openwrap/tracker/inject.go | 4 + .../pubmatic/openwrap/tracker/inject_test.go | 34 ++ modules/pubmatic/openwrap/tracker/tracker.go | 4 + .../pubmatic/openwrap/tracker/tracker_test.go | 10 + openrtb_ext/{adpod.go => openwrap.go} | 6 + .../{adpod_test.go => openwrap_test.go} | 0 openrtb_ext/request.go | 3 +- 43 files changed, 1171 insertions(+), 394 deletions(-) rename modules/pubmatic/openwrap/metrics/config/{metrics.go => multimetrics.go} (98%) rename modules/pubmatic/openwrap/metrics/config/{metrics_test.go => multimetrics_test.go} (98%) create mode 100644 modules/pubmatic/openwrap/publisherfeature/analyticsthrottle.go create mode 100644 modules/pubmatic/openwrap/publisherfeature/analyticsthrottle_test.go rename openrtb_ext/{adpod.go => openwrap.go} (98%) rename openrtb_ext/{adpod_test.go => openwrap_test.go} (100%) diff --git a/Makefile b/Makefile index 5ca684b4421..73faa5fa2fa 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ format: formatcheck: ./scripts/format.sh -f false -mockgen: mockgeninstall mockgendb mockgencache mockgenmetrics +mockgen: mockgeninstall mockgendb mockgencache mockgenmetrics mockgenlogger mockgenpublisherfeature # export GOPATH=~/go ; GOBIN=~/go/bin; export PATH=$PATH:$GOBIN mockgeninstall: diff --git a/analytics/pubmatic/logger.go b/analytics/pubmatic/logger.go index a27fa550342..6a15f5be3a5 100644 --- a/analytics/pubmatic/logger.go +++ b/analytics/pubmatic/logger.go @@ -32,7 +32,7 @@ var getUUID = func() string { // GetLogAuctionObjectAsURL will form the owlogger-url and http-headers func GetLogAuctionObjectAsURL(ao analytics.AuctionObject, rCtx *models.RequestCtx, logInfo, forRespExt bool) (string, http.Header) { - if ao.RequestWrapper == nil || ao.RequestWrapper.BidRequest == nil || rCtx == nil || rCtx.PubID == 0 { + if ao.RequestWrapper == nil || ao.RequestWrapper.BidRequest == nil || rCtx == nil || rCtx.PubID == 0 || rCtx.LoggerDisabled { return "", nil } diff --git a/analytics/pubmatic/logger_test.go b/analytics/pubmatic/logger_test.go index 60697cc571a..21bcae7d2d0 100644 --- a/analytics/pubmatic/logger_test.go +++ b/analytics/pubmatic/logger_test.go @@ -3368,6 +3368,28 @@ func TestGetLogAuctionObjectAsURL(t *testing.T) { args args want want }{ + { + name: "logger_disabled", + args: args{ + ao: analytics.AuctionObject{ + RequestWrapper: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{}, + }, + Response: &openrtb2.BidResponse{}, + }, + rCtx: &models.RequestCtx{ + Endpoint: models.EndpointV25, + LoggerDisabled: true, + PubID: 5890, + }, + logInfo: true, + forRespExt: true, + }, + want: want{ + logger: "", + header: nil, + }, + }, { name: "do not prepare owlogger if pubid is missing", args: args{ diff --git a/analytics/pubmatic/mhttp/mock/mock.go b/analytics/pubmatic/mhttp/mock/mock.go index 1c898851934..656e7f07180 100644 --- a/analytics/pubmatic/mhttp/mock/mock.go +++ b/analytics/pubmatic/mhttp/mock/mock.go @@ -1,64 +1,65 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/PubMatic-OpenWrap/prebid-server/analytics/pubmatic/mhttp (interfaces: HttpCallInterface,MultiHttpContextInterface) +// Source: github.com/PubMatic-OpenWrap/prebid-server/v2/analytics/pubmatic/mhttp (interfaces: HttpCallInterface,MultiHttpContextInterface) // Package mock_mhttp is a generated GoMock package. package mock_mhttp import ( - gomock "github.com/golang/mock/gomock" - mhttp "github.com/prebid/prebid-server/v2/analytics/pubmatic/mhttp" reflect "reflect" sync "sync" + + gomock "github.com/golang/mock/gomock" + mhttp "github.com/prebid/prebid-server/v2/analytics/pubmatic/mhttp" ) -// MockHttpCallInterface is a mock of HttpCallInterface interface +// MockHttpCallInterface is a mock of HttpCallInterface interface. type MockHttpCallInterface struct { ctrl *gomock.Controller recorder *MockHttpCallInterfaceMockRecorder } -// MockHttpCallInterfaceMockRecorder is the mock recorder for MockHttpCallInterface +// MockHttpCallInterfaceMockRecorder is the mock recorder for MockHttpCallInterface. type MockHttpCallInterfaceMockRecorder struct { mock *MockHttpCallInterface } -// NewMockHttpCallInterface creates a new mock instance +// NewMockHttpCallInterface creates a new mock instance. func NewMockHttpCallInterface(ctrl *gomock.Controller) *MockHttpCallInterface { mock := &MockHttpCallInterface{ctrl: ctrl} mock.recorder = &MockHttpCallInterfaceMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockHttpCallInterface) EXPECT() *MockHttpCallInterfaceMockRecorder { return m.recorder } -// AddCookie mocks base method +// AddCookie mocks base method. func (m *MockHttpCallInterface) AddCookie(arg0, arg1 string) { m.ctrl.T.Helper() m.ctrl.Call(m, "AddCookie", arg0, arg1) } -// AddCookie indicates an expected call of AddCookie +// AddCookie indicates an expected call of AddCookie. func (mr *MockHttpCallInterfaceMockRecorder) AddCookie(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCookie", reflect.TypeOf((*MockHttpCallInterface)(nil).AddCookie), arg0, arg1) } -// AddHeader mocks base method +// AddHeader mocks base method. func (m *MockHttpCallInterface) AddHeader(arg0, arg1 string) { m.ctrl.T.Helper() m.ctrl.Call(m, "AddHeader", arg0, arg1) } -// AddHeader indicates an expected call of AddHeader +// AddHeader indicates an expected call of AddHeader. func (mr *MockHttpCallInterfaceMockRecorder) AddHeader(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddHeader", reflect.TypeOf((*MockHttpCallInterface)(nil).AddHeader), arg0, arg1) } -// GetResponseBody mocks base method +// GetResponseBody mocks base method. func (m *MockHttpCallInterface) GetResponseBody() string { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetResponseBody") @@ -66,13 +67,13 @@ func (m *MockHttpCallInterface) GetResponseBody() string { return ret0 } -// GetResponseBody indicates an expected call of GetResponseBody +// GetResponseBody indicates an expected call of GetResponseBody. func (mr *MockHttpCallInterfaceMockRecorder) GetResponseBody() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResponseBody", reflect.TypeOf((*MockHttpCallInterface)(nil).GetResponseBody)) } -// getError mocks base method +// getError mocks base method. func (m *MockHttpCallInterface) getError() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "getError") @@ -80,60 +81,60 @@ func (m *MockHttpCallInterface) getError() error { return ret0 } -// getError indicates an expected call of getError +// getError indicates an expected call of getError. func (mr *MockHttpCallInterfaceMockRecorder) getError() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getError", reflect.TypeOf((*MockHttpCallInterface)(nil).getError)) } -// submit mocks base method +// submit mocks base method. func (m *MockHttpCallInterface) submit(arg0 *sync.WaitGroup) { m.ctrl.T.Helper() m.ctrl.Call(m, "submit", arg0) } -// submit indicates an expected call of submit +// submit indicates an expected call of submit. func (mr *MockHttpCallInterfaceMockRecorder) submit(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "submit", reflect.TypeOf((*MockHttpCallInterface)(nil).submit), arg0) } -// MockMultiHttpContextInterface is a mock of MultiHttpContextInterface interface +// MockMultiHttpContextInterface is a mock of MultiHttpContextInterface interface. type MockMultiHttpContextInterface struct { ctrl *gomock.Controller recorder *MockMultiHttpContextInterfaceMockRecorder } -// MockMultiHttpContextInterfaceMockRecorder is the mock recorder for MockMultiHttpContextInterface +// MockMultiHttpContextInterfaceMockRecorder is the mock recorder for MockMultiHttpContextInterface. type MockMultiHttpContextInterfaceMockRecorder struct { mock *MockMultiHttpContextInterface } -// NewMockMultiHttpContextInterface creates a new mock instance +// NewMockMultiHttpContextInterface creates a new mock instance. func NewMockMultiHttpContextInterface(ctrl *gomock.Controller) *MockMultiHttpContextInterface { mock := &MockMultiHttpContextInterface{ctrl: ctrl} mock.recorder = &MockMultiHttpContextInterfaceMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockMultiHttpContextInterface) EXPECT() *MockMultiHttpContextInterfaceMockRecorder { return m.recorder } -// AddHttpCall mocks base method +// AddHttpCall mocks base method. func (m *MockMultiHttpContextInterface) AddHttpCall(arg0 mhttp.HttpCallInterface) { m.ctrl.T.Helper() m.ctrl.Call(m, "AddHttpCall", arg0) } -// AddHttpCall indicates an expected call of AddHttpCall +// AddHttpCall indicates an expected call of AddHttpCall. func (mr *MockMultiHttpContextInterfaceMockRecorder) AddHttpCall(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddHttpCall", reflect.TypeOf((*MockMultiHttpContextInterface)(nil).AddHttpCall), arg0) } -// Execute mocks base method +// Execute mocks base method. func (m *MockMultiHttpContextInterface) Execute() (int, int) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Execute") @@ -142,7 +143,7 @@ func (m *MockMultiHttpContextInterface) Execute() (int, int) { return ret0, ret1 } -// Execute indicates an expected call of Execute +// Execute indicates an expected call of Execute. func (mr *MockMultiHttpContextInterfaceMockRecorder) Execute() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockMultiHttpContextInterface)(nil).Execute)) diff --git a/analytics/pubmatic/pubmatic.go b/analytics/pubmatic/pubmatic.go index 956102efea6..293003d1d2d 100644 --- a/analytics/pubmatic/pubmatic.go +++ b/analytics/pubmatic/pubmatic.go @@ -54,6 +54,11 @@ func (ow HTTPLogger) LogAuctionObject(ao *analytics.AuctionObject) { return } + if rCtx.LoggerDisabled { + // logger disabled explicitly for publisher,profile request + return + } + url, headers := GetLogAuctionObjectAsURL(*ao, rCtx, false, false) if url == "" { glog.Errorf("Failed to prepare the owlogger for pub:[%d], profile:[%d], version:[%d].", diff --git a/analytics/pubmatic/pubmatic_test.go b/analytics/pubmatic/pubmatic_test.go index 652b5dc2a37..6bef274d2e4 100644 --- a/analytics/pubmatic/pubmatic_test.go +++ b/analytics/pubmatic/pubmatic_test.go @@ -72,6 +72,38 @@ func TestLogAuctionObject(t *testing.T) { }, }, }, + { + name: "logger_disabled", + ao: &analytics.AuctionObject{ + HookExecutionOutcome: []hookexecution.StageOutcome{ + { + Groups: []hookexecution.GroupOutcome{ + { + InvocationResults: []hookexecution.HookOutcome{ + { + AnalyticsTags: hookanalytics.Analytics{ + Activities: []hookanalytics.Activity{ + { + Results: []hookanalytics.Result{ + { + Values: map[string]interface{}{ + "request-ctx": &models.RequestCtx{ + LoggerDisabled: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for _, tt := range tests { HTTPLogger{}.LogAuctionObject(tt.ao) diff --git a/exchange/events.go b/exchange/events.go index 20b5a1827d4..2ec63ccfefb 100644 --- a/exchange/events.go +++ b/exchange/events.go @@ -19,6 +19,7 @@ type eventTracking struct { accountID string enabledForAccount bool enabledForRequest bool + enabledVideoEvents bool //TODO: OPENWRAP Video Events Flag auctionTimestampMs int64 integrationType string bidderInfos config.BidderInfos @@ -31,6 +32,7 @@ func getEventTracking(requestExtPrebid *openrtb_ext.ExtRequestPrebid, ts time.Ti 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, @@ -79,9 +81,11 @@ func (ev *eventTracking) modifyBidVAST(pbsBid *entities.PbsOrtbBid, bidderName o } } - // 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) + 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) + } } } diff --git a/exchange/events_test.go b/exchange/events_test.go index 144e62f19f3..0dd3c8a9920 100644 --- a/exchange/events_test.go +++ b/exchange/events_test.go @@ -197,8 +197,9 @@ func Test_isEventAllowed(t *testing.T) { func TestModifyBidVAST(t *testing.T) { type args struct { - bidReq *openrtb2.BidRequest - bid *openrtb2.Bid + enabledVideoEvents bool + bidReq *openrtb2.BidRequest + bid *openrtb2.Bid } type want struct { tags []string @@ -211,6 +212,7 @@ func TestModifyBidVAST(t *testing.T) { { 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{}}}, }, @@ -242,6 +244,7 @@ func TestModifyBidVAST(t *testing.T) { { 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{}}}, }, @@ -279,6 +282,7 @@ func TestModifyBidVAST(t *testing.T) { ModifyingVastXmlAllowed: false, }, }, + enabledVideoEvents: tc.args.enabledVideoEvents, } ev.modifyBidVAST(&entities.PbsOrtbBid{ Bid: tc.args.bid, diff --git a/exchange/utils_ow_test.go b/exchange/utils_ow_test.go index 76509efbd04..f07ec7b1a40 100644 --- a/exchange/utils_ow_test.go +++ b/exchange/utils_ow_test.go @@ -97,10 +97,12 @@ func Test_updateContentObjectForBidder(t *testing.T) { requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: true, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: true, + }, }, }, }, @@ -156,8 +158,10 @@ func Test_updateContentObjectForBidder(t *testing.T) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{}, + }, }, }, }, @@ -210,15 +214,17 @@ func Test_updateContentObjectForBidder(t *testing.T) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: true, - Keys: []string{}, - }, - "appnexus": { - Include: false, - Keys: []string{}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: true, + Keys: []string{}, + }, + "appnexus": { + Include: false, + Keys: []string{}, + }, }, }, }, @@ -270,15 +276,17 @@ func Test_updateContentObjectForBidder(t *testing.T) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: false, - Keys: []string{}, - }, - "appnexus": { - Include: true, - Keys: []string{}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: false, + Keys: []string{}, + }, + "appnexus": { + Include: true, + Keys: []string{}, + }, }, }, }, @@ -331,15 +339,17 @@ func Test_updateContentObjectForBidder(t *testing.T) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: true, - Keys: []string{"title"}, - }, - "appnexus": { - Include: false, - Keys: []string{"genre"}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: true, + Keys: []string{"title"}, + }, + "appnexus": { + Include: false, + Keys: []string{"genre"}, + }, }, }, }, @@ -394,15 +404,17 @@ func Test_updateContentObjectForBidder(t *testing.T) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: false, - Keys: []string{"title"}, - }, - "appnexus": { - Include: true, - Keys: []string{"genre"}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: false, + Keys: []string{"title"}, + }, + "appnexus": { + Include: true, + Keys: []string{"genre"}, + }, }, }, }, @@ -463,16 +475,18 @@ func Test_updateContentObjectForBidder(t *testing.T) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "default": { - Include: true, - Keys: []string{ - "id", "episode", "series", "season", "artist", "genre", "album", "isrc", "producer", "url", "cat", "prodq", "videoquality", "context", "contentrating", "userrating", "qagmediarating", "livestream", "sourcerelationship", "len", "language", "embeddable", "data", "ext"}, - }, - "pubmatic": { - Include: true, - Keys: []string{"title", "genre"}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "default": { + Include: true, + Keys: []string{ + "id", "episode", "series", "season", "artist", "genre", "album", "isrc", "producer", "url", "cat", "prodq", "videoquality", "context", "contentrating", "userrating", "qagmediarating", "livestream", "sourcerelationship", "len", "language", "embeddable", "data", "ext"}, + }, + "pubmatic": { + Include: true, + Keys: []string{"title", "genre"}, + }, }, }, }, @@ -616,10 +630,12 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: true, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: true, + }, }, }, }, @@ -675,8 +691,10 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{}, + }, }, }, }, @@ -729,15 +747,17 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: true, - Keys: []string{}, - }, - "appnexus": { - Include: false, - Keys: []string{}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: true, + Keys: []string{}, + }, + "appnexus": { + Include: false, + Keys: []string{}, + }, }, }, }, @@ -789,15 +809,17 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: false, - Keys: []string{}, - }, - "appnexus": { - Include: true, - Keys: []string{}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: false, + Keys: []string{}, + }, + "appnexus": { + Include: true, + Keys: []string{}, + }, }, }, }, @@ -850,15 +872,17 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: true, - Keys: []string{"title"}, - }, - "appnexus": { - Include: false, - Keys: []string{"genre"}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: true, + Keys: []string{"title"}, + }, + "appnexus": { + Include: false, + Keys: []string{"genre"}, + }, }, }, }, @@ -913,15 +937,17 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "pubmatic": { - Include: false, - Keys: []string{"title"}, - }, - "appnexus": { - Include: true, - Keys: []string{"genre"}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "pubmatic": { + Include: false, + Keys: []string{"title"}, + }, + "appnexus": { + Include: true, + Keys: []string{"genre"}, + }, }, }, }, @@ -982,16 +1008,18 @@ func Benchmark_updateContentObjectForBidder(b *testing.B) { }, requestExt: &openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ - Transparency: &openrtb_ext.TransparencyExt{ - Content: map[string]openrtb_ext.TransparencyRule{ - "default": { - Include: true, - Keys: []string{ - "id", "episode", "series", "season", "artist", "genre", "album", "isrc", "producer", "url", "cat", "prodq", "videoquality", "context", "contentrating", "userrating", "qagmediarating", "livestream", "sourcerelationship", "len", "language", "embeddable", "data", "ext"}, - }, - "pubmatic": { - Include: true, - Keys: []string{"title", "genre"}, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: map[string]openrtb_ext.TransparencyRule{ + "default": { + Include: true, + Keys: []string{ + "id", "episode", "series", "season", "artist", "genre", "album", "isrc", "producer", "url", "cat", "prodq", "videoquality", "context", "contentrating", "userrating", "qagmediarating", "livestream", "sourcerelationship", "len", "language", "embeddable", "data", "ext"}, + }, + "pubmatic": { + Include: true, + Keys: []string{"title", "genre"}, + }, }, }, }, diff --git a/modules/pubmatic/openwrap/auctionresponsehook_test.go b/modules/pubmatic/openwrap/auctionresponsehook_test.go index a7f649c8239..ac61e5d9b48 100644 --- a/modules/pubmatic/openwrap/auctionresponsehook_test.go +++ b/modules/pubmatic/openwrap/auctionresponsehook_test.go @@ -1077,8 +1077,8 @@ func TestNonBRCodesInHandleAuctionResponseHook(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { o := OpenWrap{ - metricEngine: tt.getMetricsEngine(), - featureConfig: mockFeature, + metricEngine: tt.getMetricsEngine(), + pubFeatures: mockFeature, } hookResult, _ := o.handleAuctionResponseHook(tt.args.ctx, tt.args.moduleCtx, tt.args.payload) mutations := hookResult.ChangeSet.Mutations() @@ -1360,8 +1360,8 @@ func TestPrebidTargetingInHandleAuctionResponseHook(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { o := OpenWrap{ - metricEngine: tt.getMetricsEngine(), - featureConfig: mockFeature, + metricEngine: tt.getMetricsEngine(), + pubFeatures: mockFeature, } hookResult, _ := o.handleAuctionResponseHook(tt.args.ctx, tt.args.moduleCtx, tt.args.payload) mutations := hookResult.ChangeSet.Mutations() @@ -1906,9 +1906,9 @@ func TestOpenWrap_handleAuctionResponseHook(t *testing.T) { mockEngine = tt.setup() } m := OpenWrap{ - cache: mockCache, - metricEngine: mockEngine, - featureConfig: mockFeature, + cache: mockCache, + metricEngine: mockEngine, + pubFeatures: mockFeature, } moduleCtx, ok := tt.args.moduleCtx.ModuleContext["rctx"] if ok { diff --git a/modules/pubmatic/openwrap/beforevalidationhook.go b/modules/pubmatic/openwrap/beforevalidationhook.go index 899f661f88e..5cadcb6e8d0 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook.go +++ b/modules/pubmatic/openwrap/beforevalidationhook.go @@ -88,7 +88,7 @@ func (m OpenWrap) handleBeforeValidationHook( rCtx.DeviceCtx.Platform = getDevicePlatform(rCtx, payload.BidRequest) populateDeviceContext(&rCtx.DeviceCtx, payload.BidRequest.Device) - rCtx.IsTBFFeatureEnabled = m.featureConfig.IsTBFFeatureEnabled(rCtx.PubID, rCtx.ProfileID) + rCtx.IsTBFFeatureEnabled = m.pubFeatures.IsTBFFeatureEnabled(rCtx.PubID, rCtx.ProfileID) if rCtx.UidCookie == nil { m.metricEngine.RecordUidsCookieNotPresentErrorStats(rCtx.PubIDStr, rCtx.ProfileIDStr) @@ -184,6 +184,7 @@ func (m OpenWrap) handleBeforeValidationHook( requestExt.Prebid.Debug = rCtx.Debug // requestExt.Prebid.SupportDeals = rCtx.SupportDeals && rCtx.IsCTVRequest // TODO: verify usecase of Prefered deals vs Support details + requestExt.Prebid.ExtOWRequestPrebid.TrackerDisabled = rCtx.TrackerDisabled requestExt.Prebid.AlternateBidderCodes, rCtx.MarketPlaceBidders = getMarketplaceBidders(requestExt.Prebid.AlternateBidderCodes, partnerConfigMap) requestExt.Prebid.Targeting = &openrtb_ext.ExtRequestTargeting{ PriceGranularity: &priceGranularity, @@ -255,7 +256,7 @@ func (m OpenWrap) handleBeforeValidationHook( } } videoAdUnitCtx = adunitconfig.UpdateVideoObjectWithAdunitConfig(rCtx, imp, div, payload.BidRequest.Device.ConnectionType) - if rCtx.Endpoint == models.EndpointAMP && m.featureConfig.IsAmpMultiformatEnabled(rCtx.PubID) && isVideoEnabledForAMP(videoAdUnitCtx.AppliedSlotAdUnitConfig) { + 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 imp.Video = &openrtb2.Video{} diff --git a/modules/pubmatic/openwrap/beforevalidationhook_test.go b/modules/pubmatic/openwrap/beforevalidationhook_test.go index ee24a078d44..057ef5d0802 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook_test.go +++ b/modules/pubmatic/openwrap/beforevalidationhook_test.go @@ -1727,10 +1727,10 @@ func TestOpenWrap_applyVideoAdUnitConfig(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { m := &OpenWrap{ - cfg: tt.fields.cfg, - cache: tt.fields.cache, - metricEngine: tt.fields.metricEngine, - featureConfig: mockFeature, + cfg: tt.fields.cfg, + cache: tt.fields.cache, + metricEngine: tt.fields.metricEngine, + pubFeatures: mockFeature, } m.applyVideoAdUnitConfig(tt.args.rCtx, tt.args.imp) assert.Equal(t, tt.args.imp, tt.want.imp, "Imp video is not upadted as expected from adunit config") @@ -3225,10 +3225,10 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { tt.setup() } m := OpenWrap{ - cfg: tt.fields.cfg, - cache: tt.fields.cache, - metricEngine: tt.fields.metricEngine, - featureConfig: mockFeature, + cfg: tt.fields.cfg, + cache: tt.fields.cache, + metricEngine: tt.fields.metricEngine, + pubFeatures: mockFeature, } bidrequest := &openrtb2.BidRequest{} @@ -3359,10 +3359,10 @@ func TestUserAgent_handleBeforeValidationHook(t *testing.T) { } adapters.InitBidders("./static/bidder-params/") m := OpenWrap{ - cfg: tt.fields.cfg, - cache: tt.fields.cache, - metricEngine: tt.fields.metricEngine, - featureConfig: mockFeature, + cfg: tt.fields.cfg, + cache: tt.fields.cache, + metricEngine: tt.fields.metricEngine, + pubFeatures: mockFeature, } tt.args.payload.BidRequest = &openrtb2.BidRequest{} json.Unmarshal(tt.args.bidrequest, tt.args.payload.BidRequest) @@ -3740,10 +3740,10 @@ func TestVASTUnwrap_handleBeforeValidationHook(t *testing.T) { adapters.InitBidders("./static/bidder-params/") m := OpenWrap{ - cfg: tt.fields.cfg, - cache: tt.fields.cache, - metricEngine: tt.fields.metricEngine, - featureConfig: mockFeature, + cfg: tt.fields.cfg, + cache: tt.fields.cache, + metricEngine: tt.fields.metricEngine, + pubFeatures: mockFeature, } tt.args.payload.BidRequest = &openrtb2.BidRequest{} json.Unmarshal(tt.args.bidrequest, tt.args.payload.BidRequest) @@ -4041,10 +4041,10 @@ func TestImpBidCtx_handleBeforeValidationHook(t *testing.T) { } adapters.InitBidders("./static/bidder-params/") m := OpenWrap{ - cfg: tt.fields.cfg, - cache: tt.fields.cache, - metricEngine: tt.fields.metricEngine, - featureConfig: mockFeature, + cfg: tt.fields.cfg, + cache: tt.fields.cache, + metricEngine: tt.fields.metricEngine, + pubFeatures: mockFeature, } tt.args.payload.BidRequest = &openrtb2.BidRequest{} json.Unmarshal(tt.args.bidrequest, tt.args.payload.BidRequest) diff --git a/modules/pubmatic/openwrap/cache/mock/mock.go b/modules/pubmatic/openwrap/cache/mock/mock.go index ba5f92e24cf..fd2c88b0506 100644 --- a/modules/pubmatic/openwrap/cache/mock/mock.go +++ b/modules/pubmatic/openwrap/cache/mock/mock.go @@ -1,41 +1,42 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/PubMatic-OpenWrap/prebid-server/modules/pubmatic/openwrap/cache (interfaces: Cache) +// Source: github.com/PubMatic-OpenWrap/prebid-server/v2/modules/pubmatic/openwrap/cache (interfaces: Cache) // Package mock_cache is a generated GoMock package. package mock_cache import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" openrtb2 "github.com/prebid/openrtb/v20/openrtb2" models "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" adunitconfig "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" - reflect "reflect" ) -// MockCache is a mock of Cache interface +// MockCache is a mock of Cache interface. type MockCache struct { ctrl *gomock.Controller recorder *MockCacheMockRecorder } -// MockCacheMockRecorder is the mock recorder for MockCache +// MockCacheMockRecorder is the mock recorder for MockCache. type MockCacheMockRecorder struct { mock *MockCache } -// NewMockCache creates a new mock instance +// NewMockCache creates a new mock instance. func NewMockCache(ctrl *gomock.Controller) *MockCache { mock := &MockCache{ctrl: ctrl} mock.recorder = &MockCacheMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockCache) EXPECT() *MockCacheMockRecorder { return m.recorder } -// Get mocks base method +// Get mocks base method. func (m *MockCache) Get(arg0 string) (interface{}, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Get", arg0) @@ -44,13 +45,13 @@ func (m *MockCache) Get(arg0 string) (interface{}, bool) { return ret0, ret1 } -// Get indicates an expected call of Get +// Get indicates an expected call of Get. func (mr *MockCacheMockRecorder) Get(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockCache)(nil).Get), arg0) } -// GetAdunitConfigFromCache mocks base method +// GetAdunitConfigFromCache mocks base method. func (m *MockCache) GetAdunitConfigFromCache(arg0 *openrtb2.BidRequest, arg1, arg2, arg3 int) *adunitconfig.AdUnitConfig { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAdunitConfigFromCache", arg0, arg1, arg2, arg3) @@ -58,13 +59,13 @@ func (m *MockCache) GetAdunitConfigFromCache(arg0 *openrtb2.BidRequest, arg1, ar return ret0 } -// GetAdunitConfigFromCache indicates an expected call of GetAdunitConfigFromCache +// GetAdunitConfigFromCache indicates an expected call of GetAdunitConfigFromCache. func (mr *MockCacheMockRecorder) GetAdunitConfigFromCache(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAdunitConfigFromCache", reflect.TypeOf((*MockCache)(nil).GetAdunitConfigFromCache), arg0, arg1, arg2, arg3) } -// GetFSCThresholdPerDSP mocks base method +// GetFSCThresholdPerDSP mocks base method. func (m *MockCache) GetFSCThresholdPerDSP() (map[int]int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFSCThresholdPerDSP") @@ -73,13 +74,13 @@ func (m *MockCache) GetFSCThresholdPerDSP() (map[int]int, error) { return ret0, ret1 } -// GetFSCThresholdPerDSP indicates an expected call of GetFSCThresholdPerDSP +// GetFSCThresholdPerDSP indicates an expected call of GetFSCThresholdPerDSP. func (mr *MockCacheMockRecorder) GetFSCThresholdPerDSP() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFSCThresholdPerDSP", reflect.TypeOf((*MockCache)(nil).GetFSCThresholdPerDSP)) } -// GetMappingsFromCacheV25 mocks base method +// GetMappingsFromCacheV25 mocks base method. func (m *MockCache) GetMappingsFromCacheV25(arg0 models.RequestCtx, arg1 int) map[string]models.SlotMapping { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetMappingsFromCacheV25", arg0, arg1) @@ -87,13 +88,13 @@ func (m *MockCache) GetMappingsFromCacheV25(arg0 models.RequestCtx, arg1 int) ma return ret0 } -// GetMappingsFromCacheV25 indicates an expected call of GetMappingsFromCacheV25 +// GetMappingsFromCacheV25 indicates an expected call of GetMappingsFromCacheV25. func (mr *MockCacheMockRecorder) GetMappingsFromCacheV25(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMappingsFromCacheV25", reflect.TypeOf((*MockCache)(nil).GetMappingsFromCacheV25), arg0, arg1) } -// GetPartnerConfigMap mocks base method +// GetPartnerConfigMap mocks base method. func (m *MockCache) GetPartnerConfigMap(arg0, arg1, arg2 int, arg3 string) (map[int]map[string]string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPartnerConfigMap", arg0, arg1, arg2, arg3) @@ -102,13 +103,13 @@ func (m *MockCache) GetPartnerConfigMap(arg0, arg1, arg2 int, arg3 string) (map[ return ret0, ret1 } -// GetPartnerConfigMap indicates an expected call of GetPartnerConfigMap +// GetPartnerConfigMap indicates an expected call of GetPartnerConfigMap. func (mr *MockCacheMockRecorder) GetPartnerConfigMap(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPartnerConfigMap", reflect.TypeOf((*MockCache)(nil).GetPartnerConfigMap), arg0, arg1, arg2, arg3) } -// GetPublisherFeatureMap mocks base method +// GetPublisherFeatureMap mocks base method. func (m *MockCache) GetPublisherFeatureMap() (map[int]map[int]models.FeatureData, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPublisherFeatureMap") @@ -117,13 +118,13 @@ func (m *MockCache) GetPublisherFeatureMap() (map[int]map[int]models.FeatureData return ret0, ret1 } -// GetPublisherFeatureMap indicates an expected call of GetPublisherFeatureMap +// GetPublisherFeatureMap indicates an expected call of GetPublisherFeatureMap. func (mr *MockCacheMockRecorder) GetPublisherFeatureMap() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublisherFeatureMap", reflect.TypeOf((*MockCache)(nil).GetPublisherFeatureMap)) } -// GetPublisherVASTTagsFromCache mocks base method +// GetPublisherVASTTagsFromCache mocks base method. func (m *MockCache) GetPublisherVASTTagsFromCache(arg0 int) map[int]*models.VASTTag { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPublisherVASTTagsFromCache", arg0) @@ -131,13 +132,13 @@ func (m *MockCache) GetPublisherVASTTagsFromCache(arg0 int) map[int]*models.VAST return ret0 } -// GetPublisherVASTTagsFromCache indicates an expected call of GetPublisherVASTTagsFromCache +// GetPublisherVASTTagsFromCache indicates an expected call of GetPublisherVASTTagsFromCache. func (mr *MockCacheMockRecorder) GetPublisherVASTTagsFromCache(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublisherVASTTagsFromCache", reflect.TypeOf((*MockCache)(nil).GetPublisherVASTTagsFromCache), arg0) } -// GetSlotToHashValueMapFromCacheV25 mocks base method +// GetSlotToHashValueMapFromCacheV25 mocks base method. func (m *MockCache) GetSlotToHashValueMapFromCacheV25(arg0 models.RequestCtx, arg1 int) models.SlotMappingInfo { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSlotToHashValueMapFromCacheV25", arg0, arg1) @@ -145,19 +146,19 @@ func (m *MockCache) GetSlotToHashValueMapFromCacheV25(arg0 models.RequestCtx, ar return ret0 } -// GetSlotToHashValueMapFromCacheV25 indicates an expected call of GetSlotToHashValueMapFromCacheV25 +// GetSlotToHashValueMapFromCacheV25 indicates an expected call of GetSlotToHashValueMapFromCacheV25. func (mr *MockCacheMockRecorder) GetSlotToHashValueMapFromCacheV25(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotToHashValueMapFromCacheV25", reflect.TypeOf((*MockCache)(nil).GetSlotToHashValueMapFromCacheV25), arg0, arg1) } -// Set mocks base method +// Set mocks base method. func (m *MockCache) Set(arg0 string, arg1 interface{}) { m.ctrl.T.Helper() m.ctrl.Call(m, "Set", arg0, arg1) } -// Set indicates an expected call of Set +// Set indicates an expected call of Set. func (mr *MockCacheMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockCache)(nil).Set), arg0, arg1) diff --git a/modules/pubmatic/openwrap/config/config.go b/modules/pubmatic/openwrap/config/config.go index 1f5e385195a..ff72f740b6d 100755 --- a/modules/pubmatic/openwrap/config/config.go +++ b/modules/pubmatic/openwrap/config/config.go @@ -57,6 +57,7 @@ type Queries struct { GetPublisherVASTTagsQuery string GetAllDspFscPcntQuery string GetPublisherFeatureMapQuery string + GetAnalyticsThrottlingQuery string } type Cache struct { @@ -82,8 +83,9 @@ type PixelView struct { } type FeatureToggle struct { - VASTUnwrapPercent int - VASTUnwrapStatsPercent int + VASTUnwrapPercent int + VASTUnwrapStatsPercent int + AnalyticsThrottlingPercentage string } type Log struct { //Log Details diff --git a/modules/pubmatic/openwrap/database/mock/mock.go b/modules/pubmatic/openwrap/database/mock/mock.go index 3f86c625b23..4c8efaf6581 100644 --- a/modules/pubmatic/openwrap/database/mock/mock.go +++ b/modules/pubmatic/openwrap/database/mock/mock.go @@ -1,40 +1,41 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/PubMatic-OpenWrap/prebid-server/modules/pubmatic/openwrap/database (interfaces: Database) +// Source: github.com/PubMatic-OpenWrap/prebid-server/v2/modules/pubmatic/openwrap/database (interfaces: Database) // Package mock_database is a generated GoMock package. package mock_database import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" models "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" adunitconfig "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" - reflect "reflect" ) -// MockDatabase is a mock of Database interface +// MockDatabase is a mock of Database interface. type MockDatabase struct { ctrl *gomock.Controller recorder *MockDatabaseMockRecorder } -// MockDatabaseMockRecorder is the mock recorder for MockDatabase +// MockDatabaseMockRecorder is the mock recorder for MockDatabase. type MockDatabaseMockRecorder struct { mock *MockDatabase } -// NewMockDatabase creates a new mock instance +// NewMockDatabase creates a new mock instance. func NewMockDatabase(ctrl *gomock.Controller) *MockDatabase { mock := &MockDatabase{ctrl: ctrl} mock.recorder = &MockDatabaseMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockDatabase) EXPECT() *MockDatabaseMockRecorder { return m.recorder } -// GetActivePartnerConfigurations mocks base method +// GetActivePartnerConfigurations mocks base method. func (m *MockDatabase) GetActivePartnerConfigurations(arg0, arg1, arg2 int) (map[int]map[string]string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetActivePartnerConfigurations", arg0, arg1, arg2) @@ -43,13 +44,13 @@ func (m *MockDatabase) GetActivePartnerConfigurations(arg0, arg1, arg2 int) (map return ret0, ret1 } -// GetActivePartnerConfigurations indicates an expected call of GetActivePartnerConfigurations +// GetActivePartnerConfigurations indicates an expected call of GetActivePartnerConfigurations. func (mr *MockDatabaseMockRecorder) GetActivePartnerConfigurations(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActivePartnerConfigurations", reflect.TypeOf((*MockDatabase)(nil).GetActivePartnerConfigurations), arg0, arg1, arg2) } -// GetAdunitConfig mocks base method +// GetAdunitConfig mocks base method. func (m *MockDatabase) GetAdunitConfig(arg0, arg1 int) (*adunitconfig.AdUnitConfig, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAdunitConfig", arg0, arg1) @@ -58,13 +59,13 @@ func (m *MockDatabase) GetAdunitConfig(arg0, arg1 int) (*adunitconfig.AdUnitConf return ret0, ret1 } -// GetAdunitConfig indicates an expected call of GetAdunitConfig +// GetAdunitConfig indicates an expected call of GetAdunitConfig. func (mr *MockDatabaseMockRecorder) GetAdunitConfig(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAdunitConfig", reflect.TypeOf((*MockDatabase)(nil).GetAdunitConfig), arg0, arg1) } -// GetFSCThresholdPerDSP mocks base method +// GetFSCThresholdPerDSP mocks base method. func (m *MockDatabase) GetFSCThresholdPerDSP() (map[int]int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFSCThresholdPerDSP") @@ -73,13 +74,13 @@ func (m *MockDatabase) GetFSCThresholdPerDSP() (map[int]int, error) { return ret0, ret1 } -// GetFSCThresholdPerDSP indicates an expected call of GetFSCThresholdPerDSP +// GetFSCThresholdPerDSP indicates an expected call of GetFSCThresholdPerDSP. func (mr *MockDatabaseMockRecorder) GetFSCThresholdPerDSP() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFSCThresholdPerDSP", reflect.TypeOf((*MockDatabase)(nil).GetFSCThresholdPerDSP)) } -// GetMappings mocks base method +// GetMappings mocks base method. func (m *MockDatabase) GetMappings(arg0 string, arg1 map[string]models.SlotMapping) (map[string]interface{}, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetMappings", arg0, arg1) @@ -88,13 +89,13 @@ func (m *MockDatabase) GetMappings(arg0 string, arg1 map[string]models.SlotMappi return ret0, ret1 } -// GetMappings indicates an expected call of GetMappings +// GetMappings indicates an expected call of GetMappings. func (mr *MockDatabaseMockRecorder) GetMappings(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMappings", reflect.TypeOf((*MockDatabase)(nil).GetMappings), arg0, arg1) } -// GetPublisherFeatureMap mocks base method +// GetPublisherFeatureMap mocks base method. func (m *MockDatabase) GetPublisherFeatureMap() (map[int]map[int]models.FeatureData, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPublisherFeatureMap") @@ -103,13 +104,13 @@ func (m *MockDatabase) GetPublisherFeatureMap() (map[int]map[int]models.FeatureD return ret0, ret1 } -// GetPublisherFeatureMap indicates an expected call of GetPublisherFeatureMap +// GetPublisherFeatureMap indicates an expected call of GetPublisherFeatureMap. func (mr *MockDatabaseMockRecorder) GetPublisherFeatureMap() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublisherFeatureMap", reflect.TypeOf((*MockDatabase)(nil).GetPublisherFeatureMap)) } -// GetPublisherSlotNameHash mocks base method +// GetPublisherSlotNameHash mocks base method. func (m *MockDatabase) GetPublisherSlotNameHash(arg0 int) (map[string]string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPublisherSlotNameHash", arg0) @@ -118,13 +119,13 @@ func (m *MockDatabase) GetPublisherSlotNameHash(arg0 int) (map[string]string, er return ret0, ret1 } -// GetPublisherSlotNameHash indicates an expected call of GetPublisherSlotNameHash +// GetPublisherSlotNameHash indicates an expected call of GetPublisherSlotNameHash. func (mr *MockDatabaseMockRecorder) GetPublisherSlotNameHash(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublisherSlotNameHash", reflect.TypeOf((*MockDatabase)(nil).GetPublisherSlotNameHash), arg0) } -// GetPublisherVASTTags mocks base method +// GetPublisherVASTTags mocks base method. func (m *MockDatabase) GetPublisherVASTTags(arg0 int) (map[int]*models.VASTTag, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPublisherVASTTags", arg0) @@ -133,13 +134,13 @@ func (m *MockDatabase) GetPublisherVASTTags(arg0 int) (map[int]*models.VASTTag, return ret0, ret1 } -// GetPublisherVASTTags indicates an expected call of GetPublisherVASTTags +// GetPublisherVASTTags indicates an expected call of GetPublisherVASTTags. func (mr *MockDatabaseMockRecorder) GetPublisherVASTTags(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublisherVASTTags", reflect.TypeOf((*MockDatabase)(nil).GetPublisherVASTTags), arg0) } -// GetWrapperSlotMappings mocks base method +// GetWrapperSlotMappings mocks base method. func (m *MockDatabase) GetWrapperSlotMappings(arg0 map[int]map[string]string, arg1, arg2 int) (map[int][]models.SlotMapping, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetWrapperSlotMappings", arg0, arg1, arg2) @@ -148,7 +149,7 @@ func (m *MockDatabase) GetWrapperSlotMappings(arg0 map[int]map[string]string, ar return ret0, ret1 } -// GetWrapperSlotMappings indicates an expected call of GetWrapperSlotMappings +// GetWrapperSlotMappings indicates an expected call of GetWrapperSlotMappings. func (mr *MockDatabaseMockRecorder) GetWrapperSlotMappings(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWrapperSlotMappings", reflect.TypeOf((*MockDatabase)(nil).GetWrapperSlotMappings), arg0, arg1, arg2) diff --git a/modules/pubmatic/openwrap/database/mock_driver/mock.go b/modules/pubmatic/openwrap/database/mock_driver/mock.go index a8f6d808c95..c5c653194ad 100644 --- a/modules/pubmatic/openwrap/database/mock_driver/mock.go +++ b/modules/pubmatic/openwrap/database/mock_driver/mock.go @@ -7,34 +7,35 @@ package mock_driver import ( context "context" driver "database/sql/driver" - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" ) -// MockDriver is a mock of Driver interface +// MockDriver is a mock of Driver interface. type MockDriver struct { ctrl *gomock.Controller recorder *MockDriverMockRecorder } -// MockDriverMockRecorder is the mock recorder for MockDriver +// MockDriverMockRecorder is the mock recorder for MockDriver. type MockDriverMockRecorder struct { mock *MockDriver } -// NewMockDriver creates a new mock instance +// NewMockDriver creates a new mock instance. func NewMockDriver(ctrl *gomock.Controller) *MockDriver { mock := &MockDriver{ctrl: ctrl} mock.recorder = &MockDriverMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockDriver) EXPECT() *MockDriverMockRecorder { return m.recorder } -// Open mocks base method +// Open mocks base method. func (m *MockDriver) Open(arg0 string) (driver.Conn, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Open", arg0) @@ -43,36 +44,36 @@ func (m *MockDriver) Open(arg0 string) (driver.Conn, error) { return ret0, ret1 } -// Open indicates an expected call of Open +// Open indicates an expected call of Open. func (mr *MockDriverMockRecorder) Open(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockDriver)(nil).Open), arg0) } -// MockConnector is a mock of Connector interface +// MockConnector is a mock of Connector interface. type MockConnector struct { ctrl *gomock.Controller recorder *MockConnectorMockRecorder } -// MockConnectorMockRecorder is the mock recorder for MockConnector +// MockConnectorMockRecorder is the mock recorder for MockConnector. type MockConnectorMockRecorder struct { mock *MockConnector } -// NewMockConnector creates a new mock instance +// NewMockConnector creates a new mock instance. func NewMockConnector(ctrl *gomock.Controller) *MockConnector { mock := &MockConnector{ctrl: ctrl} mock.recorder = &MockConnectorMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockConnector) EXPECT() *MockConnectorMockRecorder { return m.recorder } -// Connect mocks base method +// Connect mocks base method. func (m *MockConnector) Connect(arg0 context.Context) (driver.Conn, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Connect", arg0) @@ -81,13 +82,13 @@ func (m *MockConnector) Connect(arg0 context.Context) (driver.Conn, error) { return ret0, ret1 } -// Connect indicates an expected call of Connect +// Connect indicates an expected call of Connect. func (mr *MockConnectorMockRecorder) Connect(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockConnector)(nil).Connect), arg0) } -// Driver mocks base method +// Driver mocks base method. func (m *MockConnector) Driver() driver.Driver { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Driver") @@ -95,36 +96,36 @@ func (m *MockConnector) Driver() driver.Driver { return ret0 } -// Driver indicates an expected call of Driver +// Driver indicates an expected call of Driver. func (mr *MockConnectorMockRecorder) Driver() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Driver", reflect.TypeOf((*MockConnector)(nil).Driver)) } -// MockConn is a mock of Conn interface +// MockConn is a mock of Conn interface. type MockConn struct { ctrl *gomock.Controller recorder *MockConnMockRecorder } -// MockConnMockRecorder is the mock recorder for MockConn +// MockConnMockRecorder is the mock recorder for MockConn. type MockConnMockRecorder struct { mock *MockConn } -// NewMockConn creates a new mock instance +// NewMockConn creates a new mock instance. func NewMockConn(ctrl *gomock.Controller) *MockConn { mock := &MockConn{ctrl: ctrl} mock.recorder = &MockConnMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockConn) EXPECT() *MockConnMockRecorder { return m.recorder } -// Begin mocks base method +// Begin mocks base method. func (m *MockConn) Begin() (driver.Tx, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Begin") @@ -133,13 +134,13 @@ func (m *MockConn) Begin() (driver.Tx, error) { return ret0, ret1 } -// Begin indicates an expected call of Begin +// Begin indicates an expected call of Begin. func (mr *MockConnMockRecorder) Begin() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Begin", reflect.TypeOf((*MockConn)(nil).Begin)) } -// Close mocks base method +// Close mocks base method. func (m *MockConn) Close() error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Close") @@ -147,13 +148,13 @@ func (m *MockConn) Close() error { return ret0 } -// Close indicates an expected call of Close +// Close indicates an expected call of Close. func (mr *MockConnMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConn)(nil).Close)) } -// Prepare mocks base method +// Prepare mocks base method. func (m *MockConn) Prepare(arg0 string) (driver.Stmt, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Prepare", arg0) @@ -162,36 +163,36 @@ func (m *MockConn) Prepare(arg0 string) (driver.Stmt, error) { return ret0, ret1 } -// Prepare indicates an expected call of Prepare +// Prepare indicates an expected call of Prepare. func (mr *MockConnMockRecorder) Prepare(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockConn)(nil).Prepare), arg0) } -// MockDriverContext is a mock of DriverContext interface +// MockDriverContext is a mock of DriverContext interface. type MockDriverContext struct { ctrl *gomock.Controller recorder *MockDriverContextMockRecorder } -// MockDriverContextMockRecorder is the mock recorder for MockDriverContext +// MockDriverContextMockRecorder is the mock recorder for MockDriverContext. type MockDriverContextMockRecorder struct { mock *MockDriverContext } -// NewMockDriverContext creates a new mock instance +// NewMockDriverContext creates a new mock instance. func NewMockDriverContext(ctrl *gomock.Controller) *MockDriverContext { mock := &MockDriverContext{ctrl: ctrl} mock.recorder = &MockDriverContextMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockDriverContext) EXPECT() *MockDriverContextMockRecorder { return m.recorder } -// OpenConnector mocks base method +// OpenConnector mocks base method. func (m *MockDriverContext) OpenConnector(arg0 string) (driver.Connector, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "OpenConnector", arg0) @@ -200,7 +201,7 @@ func (m *MockDriverContext) OpenConnector(arg0 string) (driver.Connector, error) return ret0, ret1 } -// OpenConnector indicates an expected call of OpenConnector +// OpenConnector indicates an expected call of OpenConnector. func (mr *MockDriverContextMockRecorder) OpenConnector(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenConnector", reflect.TypeOf((*MockDriverContext)(nil).OpenConnector), arg0) diff --git a/modules/pubmatic/openwrap/endpoints/legacy/openrtb/v25/video.go b/modules/pubmatic/openwrap/endpoints/legacy/openrtb/v25/video.go index 50076893bce..213ecaadbad 100644 --- a/modules/pubmatic/openwrap/endpoints/legacy/openrtb/v25/video.go +++ b/modules/pubmatic/openwrap/endpoints/legacy/openrtb/v25/video.go @@ -336,8 +336,10 @@ func ConvertVideoToAuctionRequest(payload hookstage.EntrypointPayload, result *h ExtRequest: openrtb_ext.ExtRequest{ Prebid: openrtb_ext.ExtRequestPrebid{ Debug: getValueForKeyFromParams(models.DEBUG_KEY, appReq, values, redirectQueryParams) == "1", - Transparency: &openrtb_ext.TransparencyExt{ - Content: transparency, + ExtOWRequestPrebid: openrtb_ext.ExtOWRequestPrebid{ + Transparency: &openrtb_ext.TransparencyExt{ + Content: transparency, + }, }, }, }, diff --git a/modules/pubmatic/openwrap/entrypointhook.go b/modules/pubmatic/openwrap/entrypointhook.go index 7e619b8f65f..b6470994fb8 100644 --- a/modules/pubmatic/openwrap/entrypointhook.go +++ b/modules/pubmatic/openwrap/entrypointhook.go @@ -133,6 +133,8 @@ func (m OpenWrap) handleEntrypointHook( rCtx.PubID = pubid } + rCtx.LoggerDisabled, rCtx.TrackerDisabled = m.pubFeatures.IsAnalyticsTrackingThrottled(rCtx.PubID, rCtx.ProfileID) + result.Reject = false return result, nil } diff --git a/modules/pubmatic/openwrap/entrypointhook_test.go b/modules/pubmatic/openwrap/entrypointhook_test.go index c893abeee49..d1a588a7dc1 100644 --- a/modules/pubmatic/openwrap/entrypointhook_test.go +++ b/modules/pubmatic/openwrap/entrypointhook_test.go @@ -13,6 +13,7 @@ import ( 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" + mock_publisherfeatures "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/publisherfeature/mock" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) @@ -20,6 +21,7 @@ import ( func TestOpenWrap_handleEntrypointHook(t *testing.T) { ctrl := gomock.NewController(t) mockEngine := mock_metrics.NewMockMetricsEngine(ctrl) + defer ctrl.Finish() type fields struct { @@ -30,7 +32,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { in0 context.Context miCtx hookstage.ModuleInvocationContext payload hookstage.EntrypointPayload - setup func(*mock_metrics.MockMetricsEngine) + setup func(*mock_metrics.MockMetricsEngine, *mock_publisherfeatures.MockFeature) } tests := []struct { name string @@ -57,7 +59,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -94,7 +96,9 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) + }, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -157,7 +161,9 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1,"wiid":"4df09505-d0b2-4d70-94d9-dc41e8e777f7"}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) + }, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -205,7 +211,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileids":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) { + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { mme.EXPECT().RecordBadRequests(gomock.Any(), 700) }, }, @@ -238,7 +244,9 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{"profileid":43563,"versionid":1}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) + }, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -297,7 +305,9 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{"profileid":43563,"versionid":1}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false,"debug":true}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) + }, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -356,7 +366,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) { + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { mme.EXPECT().RecordBadRequests(gomock.Any(), 700) }, }, @@ -389,7 +399,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -418,7 +428,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -456,7 +466,9 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine) {}, + setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) + }, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -496,12 +508,14 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + mockPubFeature := mock_publisherfeatures.NewMockFeature(ctrl) - tt.args.setup(mockEngine) + tt.args.setup(mockEngine, mockPubFeature) m := OpenWrap{ cfg: tt.fields.cfg, cache: tt.fields.cache, metricEngine: mockEngine, + pubFeatures: mockPubFeature, } got, err := m.handleEntrypointHook(tt.args.in0, tt.args.miCtx, tt.args.payload) assert.Equal(t, err, tt.wantErr) diff --git a/modules/pubmatic/openwrap/metrics/config/metrics.go b/modules/pubmatic/openwrap/metrics/config/multimetrics.go similarity index 98% rename from modules/pubmatic/openwrap/metrics/config/metrics.go rename to modules/pubmatic/openwrap/metrics/config/multimetrics.go index cb5609d457c..1c773f704b4 100644 --- a/modules/pubmatic/openwrap/metrics/config/metrics.go +++ b/modules/pubmatic/openwrap/metrics/config/multimetrics.go @@ -493,3 +493,10 @@ func (me *MultiMetricsEngine) RecordUnwrapRespTime(accountId, wraperCnt string, thisME.RecordUnwrapRespTime(accountId, wraperCnt, respTime) } } + +// RecordAnalyticsTrackingThrottled record analytics throttling at publisher profile level +func (me *MultiMetricsEngine) RecordAnalyticsTrackingThrottled(pubid, profileid, analyticsType string) { + for _, thisME := range *me { + thisME.RecordAnalyticsTrackingThrottled(pubid, profileid, analyticsType) + } +} diff --git a/modules/pubmatic/openwrap/metrics/config/metrics_test.go b/modules/pubmatic/openwrap/metrics/config/multimetrics_test.go similarity index 98% rename from modules/pubmatic/openwrap/metrics/config/metrics_test.go rename to modules/pubmatic/openwrap/metrics/config/multimetrics_test.go index 0baf16df899..25c183e08c9 100644 --- a/modules/pubmatic/openwrap/metrics/config/metrics_test.go +++ b/modules/pubmatic/openwrap/metrics/config/multimetrics_test.go @@ -206,6 +206,7 @@ func TestRecordFunctionForMultiMetricsEngine(t *testing.T) { mockEngine.EXPECT().RecordGetProfileDataTime(endpoint, profile, getTime) mockEngine.EXPECT().RecordSendLoggerDataTime(endpoint, profile, sendTime) mockEngine.EXPECT().RecordDBQueryFailure(queryType, publisher, profile) + mockEngine.EXPECT().RecordAnalyticsTrackingThrottled(publisher, profile, "logger") mockEngine.EXPECT().Shutdown() mockEngine.EXPECT().RecordRequest(metrics.Labels{RType: "video", RequestStatus: "success"}) @@ -271,6 +272,7 @@ func TestRecordFunctionForMultiMetricsEngine(t *testing.T) { multiMetricEngine.RecordGetProfileDataTime(endpoint, profile, getTime) multiMetricEngine.RecordSendLoggerDataTime(endpoint, profile, sendTime) multiMetricEngine.RecordDBQueryFailure(queryType, publisher, profile) + multiMetricEngine.RecordAnalyticsTrackingThrottled(publisher, profile, "logger") multiMetricEngine.Shutdown() multiMetricEngine.RecordRequest(metrics.Labels{RType: "video", RequestStatus: "success"}) diff --git a/modules/pubmatic/openwrap/metrics/metrics.go b/modules/pubmatic/openwrap/metrics/metrics.go index c46edabce7b..228dee246be 100644 --- a/modules/pubmatic/openwrap/metrics/metrics.go +++ b/modules/pubmatic/openwrap/metrics/metrics.go @@ -75,6 +75,7 @@ type MetricsEngine interface { RecordOWServerPanic(endpoint, methodName, nodeName, podName string) RecordAmpVideoRequests(pubid, profileid string) RecordAmpVideoResponses(pubid, profileid string) + RecordAnalyticsTrackingThrottled(pubid, profileid, analyticsType string) // VAST Unwrap metrics RecordUnwrapRequestStatus(accountId, bidder, status string) diff --git a/modules/pubmatic/openwrap/metrics/mock/mock.go b/modules/pubmatic/openwrap/metrics/mock/mock.go index 4369f29a400..3ba1464ac93 100644 --- a/modules/pubmatic/openwrap/metrics/mock/mock.go +++ b/modules/pubmatic/openwrap/metrics/mock/mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/PubMatic-OpenWrap/prebid-server/modules/pubmatic/openwrap/metrics (interfaces: MetricsEngine) +// Source: github.com/PubMatic-OpenWrap/prebid-server/v2/modules/pubmatic/openwrap/metrics (interfaces: MetricsEngine) // Package mock_metrics is a generated GoMock package. package mock_metrics @@ -59,6 +59,42 @@ func (mr *MockMetricsEngineMockRecorder) RecordAdPodImpressionYield(arg0, arg1, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordAdPodImpressionYield", reflect.TypeOf((*MockMetricsEngine)(nil).RecordAdPodImpressionYield), arg0, arg1, arg2) } +// RecordAmpVideoRequests mocks base method. +func (m *MockMetricsEngine) RecordAmpVideoRequests(arg0, arg1 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordAmpVideoRequests", arg0, arg1) +} + +// RecordAmpVideoRequests indicates an expected call of RecordAmpVideoRequests. +func (mr *MockMetricsEngineMockRecorder) RecordAmpVideoRequests(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordAmpVideoRequests", reflect.TypeOf((*MockMetricsEngine)(nil).RecordAmpVideoRequests), arg0, arg1) +} + +// RecordAmpVideoResponses mocks base method. +func (m *MockMetricsEngine) RecordAmpVideoResponses(arg0, arg1 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordAmpVideoResponses", arg0, arg1) +} + +// RecordAmpVideoResponses indicates an expected call of RecordAmpVideoResponses. +func (mr *MockMetricsEngineMockRecorder) RecordAmpVideoResponses(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordAmpVideoResponses", reflect.TypeOf((*MockMetricsEngine)(nil).RecordAmpVideoResponses), arg0, arg1) +} + +// RecordAnalyticsTrackingThrottled mocks base method. +func (m *MockMetricsEngine) RecordAnalyticsTrackingThrottled(arg0, arg1, arg2 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordAnalyticsTrackingThrottled", arg0, arg1, arg2) +} + +// RecordAnalyticsTrackingThrottled indicates an expected call of RecordAnalyticsTrackingThrottled. +func (mr *MockMetricsEngineMockRecorder) RecordAnalyticsTrackingThrottled(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordAnalyticsTrackingThrottled", reflect.TypeOf((*MockMetricsEngine)(nil).RecordAnalyticsTrackingThrottled), arg0, arg1, arg2) +} + // RecordBadRequests mocks base method. func (m *MockMetricsEngine) RecordBadRequests(arg0 string, arg1 int) { m.ctrl.T.Helper() @@ -89,30 +125,6 @@ func (m *MockMetricsEngine) RecordBidResponseByDealCountInPBS(arg0, arg1, arg2, m.ctrl.Call(m, "RecordBidResponseByDealCountInPBS", arg0, arg1, arg2, arg3) } -// RecordAmpVideoRequests mocks base method -func (m *MockMetricsEngine) RecordAmpVideoRequests(arg0, arg1 string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordAmpVideoRequests", arg0, arg1) -} - -// RecordAmpVideoRequests indicates an expected call of RecordAmpVideoRequests -func (mr *MockMetricsEngineMockRecorder) RecordAmpVideoRequests(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordAmpVideoRequests", reflect.TypeOf((*MockMetricsEngine)(nil).RecordAmpVideoRequests), arg0, arg1) -} - -// RecordAmpVideoResponses mocks base method -func (m *MockMetricsEngine) RecordAmpVideoResponses(arg0, arg1 string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordAmpVideoResponses", arg0, arg1) -} - -// RecordAmpVideoResponses indicates an expected call of RecordAmpVideoResponses -func (mr *MockMetricsEngineMockRecorder) RecordAmpVideoResponses(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordAmpVideoResponses", reflect.TypeOf((*MockMetricsEngine)(nil).RecordAmpVideoResponses), arg0, arg1) -} - // RecordBidResponseByDealCountInPBS indicates an expected call of RecordBidResponseByDealCountInPBS. func (mr *MockMetricsEngineMockRecorder) RecordBidResponseByDealCountInPBS(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() @@ -251,6 +263,18 @@ func (mr *MockMetricsEngineMockRecorder) RecordGetProfileDataTime(arg0, arg1, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordGetProfileDataTime", reflect.TypeOf((*MockMetricsEngine)(nil).RecordGetProfileDataTime), arg0, arg1, arg2) } +// RecordHTTPCounter mocks base method. +func (m *MockMetricsEngine) RecordHTTPCounter() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordHTTPCounter") +} + +// RecordHTTPCounter indicates an expected call of RecordHTTPCounter. +func (mr *MockMetricsEngineMockRecorder) RecordHTTPCounter() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHTTPCounter", reflect.TypeOf((*MockMetricsEngine)(nil).RecordHTTPCounter)) +} + // RecordImpDisabledViaConfigStats mocks base method. func (m *MockMetricsEngine) RecordImpDisabledViaConfigStats(arg0, arg1, arg2 string) { m.ctrl.T.Helper() @@ -671,96 +695,86 @@ func (mr *MockMetricsEngineMockRecorder) RecordUidsCookieNotPresentErrorStats(ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUidsCookieNotPresentErrorStats", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUidsCookieNotPresentErrorStats), arg0, arg1) } -// RecordVideoImpDisabledViaConnTypeStats mocks base method. -func (m *MockMetricsEngine) RecordVideoImpDisabledViaConnTypeStats(arg0, arg1 string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordVideoImpDisabledViaConnTypeStats", arg0, arg1) -} - -// RecordVideoImpDisabledViaConnTypeStats indicates an expected call of RecordVideoImpDisabledViaConnTypeStats. -func (mr *MockMetricsEngineMockRecorder) RecordVideoImpDisabledViaConnTypeStats(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordVideoImpDisabledViaConnTypeStats", reflect.TypeOf((*MockMetricsEngine)(nil).RecordVideoImpDisabledViaConnTypeStats), arg0, arg1) -} - -// RecordVideoInstlImpsStats mocks base method. -func (m *MockMetricsEngine) RecordVideoInstlImpsStats(arg0, arg1 string) { +// RecordUnwrapRequestStatus mocks base method. +func (m *MockMetricsEngine) RecordUnwrapRequestStatus(arg0, arg1, arg2 string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordVideoInstlImpsStats", arg0, arg1) + m.ctrl.Call(m, "RecordUnwrapRequestStatus", arg0, arg1, arg2) } -// RecordVideoInstlImpsStats indicates an expected call of RecordVideoInstlImpsStats. -func (mr *MockMetricsEngineMockRecorder) RecordVideoInstlImpsStats(arg0, arg1 interface{}) *gomock.Call { +// RecordUnwrapRequestStatus indicates an expected call of RecordUnwrapRequestStatus. +func (mr *MockMetricsEngineMockRecorder) RecordUnwrapRequestStatus(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordVideoInstlImpsStats", reflect.TypeOf((*MockMetricsEngine)(nil).RecordVideoInstlImpsStats), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapRequestStatus", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapRequestStatus), arg0, arg1, arg2) } -// Shutdown mocks base method. -func (m *MockMetricsEngine) Shutdown() { +// RecordUnwrapRequestTime mocks base method. +func (m *MockMetricsEngine) RecordUnwrapRequestTime(arg0, arg1 string, arg2 time.Duration) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Shutdown") + m.ctrl.Call(m, "RecordUnwrapRequestTime", arg0, arg1, arg2) } -// Shutdown indicates an expected call of Shutdown. -func (mr *MockMetricsEngineMockRecorder) Shutdown() *gomock.Call { +// RecordUnwrapRequestTime indicates an expected call of RecordUnwrapRequestTime. +func (mr *MockMetricsEngineMockRecorder) RecordUnwrapRequestTime(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Shutdown", reflect.TypeOf((*MockMetricsEngine)(nil).Shutdown)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapRequestTime", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapRequestTime), arg0, arg1, arg2) } -// RecordHTTPCounter mocks base method. -func (m *MockMetricsEngine) RecordHTTPCounter() { +// RecordUnwrapRespTime mocks base method. +func (m *MockMetricsEngine) RecordUnwrapRespTime(arg0, arg1 string, arg2 time.Duration) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordHTTPCounter") + m.ctrl.Call(m, "RecordUnwrapRespTime", arg0, arg1, arg2) } -// RecordHTTPCounter indicates an expected call of RecordHTTPCounter. -func (mr *MockMetricsEngineMockRecorder) RecordHTTPCounter() *gomock.Call { +// RecordUnwrapRespTime indicates an expected call of RecordUnwrapRespTime. +func (mr *MockMetricsEngineMockRecorder) RecordUnwrapRespTime(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordHTTPCounter", reflect.TypeOf((*MockMetricsEngine)(nil).RecordHTTPCounter)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapRespTime", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapRespTime), arg0, arg1, arg2) } -// RecordUnwrapRequestStatus mocks base method -func (m *MockMetricsEngine) RecordUnwrapRequestStatus(arg0, arg1, arg2 string) { +// RecordUnwrapWrapperCount mocks base method. +func (m *MockMetricsEngine) RecordUnwrapWrapperCount(arg0, arg1, arg2 string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordUnwrapRequestStatus", arg0, arg1, arg2) + m.ctrl.Call(m, "RecordUnwrapWrapperCount", arg0, arg1, arg2) } -// RecordUnwrapRequestStatus indicates an expected call of RecordUnwrapRequestStatus -func (mr *MockMetricsEngineMockRecorder) RecordUnwrapRequestStatus(arg0, arg1, arg2 interface{}) *gomock.Call { +// RecordUnwrapWrapperCount indicates an expected call of RecordUnwrapWrapperCount. +func (mr *MockMetricsEngineMockRecorder) RecordUnwrapWrapperCount(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapRequestStatus", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapRequestStatus), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapWrapperCount", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapWrapperCount), arg0, arg1, arg2) } -func (m *MockMetricsEngine) RecordUnwrapWrapperCount(arg0, arg1, arg2 string) { +// RecordVideoImpDisabledViaConnTypeStats mocks base method. +func (m *MockMetricsEngine) RecordVideoImpDisabledViaConnTypeStats(arg0, arg1 string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordUnwrapWrapperCount", arg0, arg1, arg2) + m.ctrl.Call(m, "RecordVideoImpDisabledViaConnTypeStats", arg0, arg1) } -// RecordUnwrapRequestStatus indicates an expected call of RecordUnwrapRequestStatus -func (mr *MockMetricsEngineMockRecorder) RecordUnwrapWrapperCount(arg0, arg1, arg2 interface{}) *gomock.Call { +// RecordVideoImpDisabledViaConnTypeStats indicates an expected call of RecordVideoImpDisabledViaConnTypeStats. +func (mr *MockMetricsEngineMockRecorder) RecordVideoImpDisabledViaConnTypeStats(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapWrapperCount", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapWrapperCount), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordVideoImpDisabledViaConnTypeStats", reflect.TypeOf((*MockMetricsEngine)(nil).RecordVideoImpDisabledViaConnTypeStats), arg0, arg1) } -// accountId string, bidder string, respTime time.Duration -func (m *MockMetricsEngine) RecordUnwrapRequestTime(arg0, arg1 string, arg2 time.Duration) { +// RecordVideoInstlImpsStats mocks base method. +func (m *MockMetricsEngine) RecordVideoInstlImpsStats(arg0, arg1 string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordUnwrapRequestTime", arg0, arg1, arg2) + m.ctrl.Call(m, "RecordVideoInstlImpsStats", arg0, arg1) } -// RecordUnwrapRequestTime indicates an expected call of RecordUnwrapRequestTime -func (mr *MockMetricsEngineMockRecorder) RecordUnwrapRequestTime(arg0, arg1, arg2 interface{}) *gomock.Call { +// RecordVideoInstlImpsStats indicates an expected call of RecordVideoInstlImpsStats. +func (mr *MockMetricsEngineMockRecorder) RecordVideoInstlImpsStats(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapRequestTime", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapRequestTime), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordVideoInstlImpsStats", reflect.TypeOf((*MockMetricsEngine)(nil).RecordVideoInstlImpsStats), arg0, arg1) } -func (m *MockMetricsEngine) RecordUnwrapRespTime(arg0, arg1 string, arg2 time.Duration) { +// Shutdown mocks base method. +func (m *MockMetricsEngine) Shutdown() { m.ctrl.T.Helper() - m.ctrl.Call(m, "RecordUnwrapRespTime", arg0, arg1, arg2) + m.ctrl.Call(m, "Shutdown") } -// RecordUnwrapRespTime indicates an expected call of RecordUnwrapRespTime -func (mr *MockMetricsEngineMockRecorder) RecordUnwrapRespTime(arg0, arg1, arg2 interface{}) *gomock.Call { +// Shutdown indicates an expected call of Shutdown. +func (mr *MockMetricsEngineMockRecorder) Shutdown() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordUnwrapRespTime", reflect.TypeOf((*MockMetricsEngine)(nil).RecordUnwrapRespTime), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Shutdown", reflect.TypeOf((*MockMetricsEngine)(nil).Shutdown)) } diff --git a/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go b/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go index f4b60bdf7ed..60d3baad4c8 100644 --- a/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go +++ b/modules/pubmatic/openwrap/metrics/prometheus/prometheus.go @@ -70,6 +70,7 @@ type Metrics struct { owRequestTime *prometheus.HistogramVec ampVideoRequests *prometheus.CounterVec ampVideoResponses *prometheus.CounterVec + analyticsThrottle *prometheus.CounterVec // VAST Unwrap requests *prometheus.CounterVec @@ -79,20 +80,21 @@ type Metrics struct { } const ( - pubIDLabel = "pub_id" - profileIDLabel = "profile_id" - partnerLabel = "partner" - platformLabel = "platform" - endpointLabel = "endpoint" // TODO- apiTypeLabel ? - apiTypeLabel = "api_type" - impFormatLabel = "imp_format" //TODO -confirm ? - adFormatLabel = "ad_format" - sourceLabel = "source" //TODO -confirm ? - nbrLabel = "nbr" // TODO - errcode ? - errorLabel = "error" - hostLabel = "host" // combination of node:pod - methodLabel = "method" - queryTypeLabel = "query_type" + pubIDLabel = "pub_id" + profileIDLabel = "profile_id" + partnerLabel = "partner" + platformLabel = "platform" + endpointLabel = "endpoint" // TODO- apiTypeLabel ? + apiTypeLabel = "api_type" + impFormatLabel = "imp_format" //TODO -confirm ? + adFormatLabel = "ad_format" + sourceLabel = "source" //TODO -confirm ? + nbrLabel = "nbr" // TODO - errcode ? + errorLabel = "error" + hostLabel = "host" // combination of node:pod + methodLabel = "method" + queryTypeLabel = "query_type" + analyticsTypeLabel = "an_type" ) var standardTimeBuckets = []float64{0.05, 0.1, 0.15, 0.20, 0.25, 0.3, 0.4, 0.5, 0.75, 1} @@ -263,6 +265,11 @@ func newMetrics(cfg *config.PrometheusMetrics, promRegistry *prometheus.Registry "Count of failures to send the logger to analytics endpoint at publisher and profile level", []string{pubIDLabel, profileIDLabel}, ) + metrics.analyticsThrottle = newCounter(cfg, promRegistry, + "analytics_throttle", + "Count of throttled analytics logger and tracker requestss", + []string{pubIDLabel, profileIDLabel, analyticsTypeLabel}) + metrics.requests = newCounter(cfg, promRegistry, "vastunwrap_status", "Count of vast unwrap requests labeled by status", @@ -486,6 +493,15 @@ func (m *Metrics) RecordHTTPCounter() { m.httpCounter.With(nil).Inc() } +// RecordAnalyticsTrackingThrottled record analytics throttling at publisher profile level +func (m *Metrics) RecordAnalyticsTrackingThrottled(pubid, profileid, analyticsType string) { + m.analyticsThrottle.With(prometheus.Labels{ + pubIDLabel: pubid, + profileIDLabel: profileid, + analyticsTypeLabel: analyticsType, + }).Inc() +} + // TODO - really need ? func (m *Metrics) RecordPBSAuctionRequestsStats() {} diff --git a/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go b/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go index e920cf132c1..59fbae851b5 100644 --- a/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go +++ b/modules/pubmatic/openwrap/metrics/stats/tcp_stats.go @@ -346,3 +346,4 @@ func (st *StatsTCP) RecordUnwrapRequestStatus(accountId, bidder, status string) func (st *StatsTCP) RecordUnwrapWrapperCount(accountId, bidder, wrapper_count string) {} func (st *StatsTCP) RecordUnwrapRequestTime(accountId, bidder string, respTime time.Duration) {} func (st *StatsTCP) RecordUnwrapRespTime(accountId, wraperCnt string, respTime time.Duration) {} +func (st *StatsTCP) RecordAnalyticsTrackingThrottled(pubid, profileid, analyticsType string) {} diff --git a/modules/pubmatic/openwrap/models/constants.go b/modules/pubmatic/openwrap/models/constants.go index 5690a07c2ac..82e44955498 100755 --- a/modules/pubmatic/openwrap/models/constants.go +++ b/modules/pubmatic/openwrap/models/constants.go @@ -472,16 +472,17 @@ const ( // constants for query_type label in stats const ( - PartnerConfigQuery = "GetPartnerConfig" - WrapperSlotMappingsQuery = "GetWrapperSlotMappingsQuery" - WrapperLiveVersionSlotMappings = "GetWrapperLiveVersionSlotMappings" - AdunitConfigQuery = "GetAdunitConfigQuery" - AdunitConfigForLiveVersion = "GetAdunitConfigForLiveVersion" - SlotNameHash = "GetSlotNameHash" - PublisherVASTTagsQuery = "GetPublisherVASTTagsQuery" - AllDspFscPcntQuery = "GetAllDspFscPcntQuery" - AdUnitFailUnmarshal = "GetAdUnitUnmarshal" - PublisherFeatureMapQuery = "GetPublisherFeatureMapQuery" + PartnerConfigQuery = "GetPartnerConfig" + WrapperSlotMappingsQuery = "GetWrapperSlotMappingsQuery" + WrapperLiveVersionSlotMappings = "GetWrapperLiveVersionSlotMappings" + AdunitConfigQuery = "GetAdunitConfigQuery" + AdunitConfigForLiveVersion = "GetAdunitConfigForLiveVersion" + SlotNameHash = "GetSlotNameHash" + PublisherVASTTagsQuery = "GetPublisherVASTTagsQuery" + AllDspFscPcntQuery = "GetAllDspFscPcntQuery" + AdUnitFailUnmarshal = "GetAdUnitUnmarshal" + PublisherFeatureMapQuery = "GetPublisherFeatureMapQuery" + AnalyticsThrottlingPercentageQuery = "GetAnalyticsThrottlingPercentage" //DisplayVersionInnerQuery = "DisplayVersionInnerQuery" //LiveVersionInnerQuery = "LiveVersionInnerQuery" //PMSlotToMappings = "GetPMSlotToMappings" @@ -518,7 +519,8 @@ const ( // constants for feature id const ( - FeatureFSC = 1 - FeatureTBF = 2 - FeatureAMPMultiFormat = 3 + FeatureFSC = 1 + FeatureTBF = 2 + FeatureAMPMultiFormat = 3 + FeatureAnalyticsThrottle = 4 ) diff --git a/modules/pubmatic/openwrap/models/openwrap.go b/modules/pubmatic/openwrap/models/openwrap.go index 8f92f25a0c4..90b47315275 100644 --- a/modules/pubmatic/openwrap/models/openwrap.go +++ b/modules/pubmatic/openwrap/models/openwrap.go @@ -101,6 +101,8 @@ type RequestCtx struct { IsTBFFeatureEnabled bool VastUnwrapEnabled bool VastUnwrapStatsEnabled bool + LoggerDisabled bool + TrackerDisabled bool } type OwBid struct { diff --git a/modules/pubmatic/openwrap/openwrap.go b/modules/pubmatic/openwrap/openwrap.go index 9b6702a5c2c..4da375400e6 100644 --- a/modules/pubmatic/openwrap/openwrap.go +++ b/modules/pubmatic/openwrap/openwrap.go @@ -36,7 +36,7 @@ type OpenWrap struct { cache cache.Cache metricEngine metrics.MetricsEngine currencyConversion currency.Conversions - featureConfig publisherfeature.Feature + pubFeatures publisherfeature.Feature unwrap unwrap.Unwrap } @@ -78,8 +78,12 @@ func initOpenWrap(rawCfg json.RawMessage, moduleDeps moduledeps.ModuleDeps) (Ope owCache := ow_gocache.New(cache, db, cfg.Cache, &metricEngine) // Init Feature reloader service - featureConfig := publisherfeature.New(owCache, cfg.Cache.CacheDefaultExpiry) - featureConfig.Start() + pubFeatures := publisherfeature.New(publisherfeature.Config{ + Cache: owCache, + DefaultExpiry: cfg.Cache.CacheDefaultExpiry, + AnalyticsThrottleList: cfg.Features.AnalyticsThrottlingPercentage, + }) + pubFeatures.Start() // Init VAST Unwrap vastunwrap.InitUnWrapperConfig(cfg.VastUnwrapCfg) @@ -92,7 +96,7 @@ func initOpenWrap(rawCfg json.RawMessage, moduleDeps moduledeps.ModuleDeps) (Ope cache: owCache, metricEngine: &metricEngine, currencyConversion: moduleDeps.CurrencyConversion, - featureConfig: featureConfig, + pubFeatures: pubFeatures, unwrap: uw, } }) diff --git a/modules/pubmatic/openwrap/openwrap_sshb.go b/modules/pubmatic/openwrap/openwrap_sshb.go index b3f26fb581e..f56f6994003 100644 --- a/modules/pubmatic/openwrap/openwrap_sshb.go +++ b/modules/pubmatic/openwrap/openwrap_sshb.go @@ -43,7 +43,7 @@ func (ow *OpenWrap) SetMetricEngine(m metrics.MetricsEngine) { // GetFeature Temporary function to expose feature to SSHB func (ow *OpenWrap) GetFeature() publisherfeature.Feature { - return ow.featureConfig + return ow.pubFeatures } // getVastUnwrapperEnable checks for Vast unwrp is enabled in given context diff --git a/modules/pubmatic/openwrap/publisherfeature/analyticsthrottle.go b/modules/pubmatic/openwrap/publisherfeature/analyticsthrottle.go new file mode 100644 index 00000000000..05525d85a68 --- /dev/null +++ b/modules/pubmatic/openwrap/publisherfeature/analyticsthrottle.go @@ -0,0 +1,173 @@ +package publisherfeature + +import ( + "fmt" + "math/rand" + "strconv" + "strings" + + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" +) + +const ( + errInvalidAnalyticsThrottlingKeyFormat = `[AnalyticsThrottling] status:[INVALID] part:[%v] key:[%v]` + keySeparator = "," + keyPartSeparator = ":" + allProfiles = 0 +) + +const ( + keyPartPubID = 0 + keyPartProfileID = 1 + keyPartLoggerPercentage = 2 + keyPartTrackerPercentage = 3 +) + +// percentageValue type defines throttling percentage for analytics logger and tracker +type percentageValue struct { + logger int + tracker int +} + +func (p *percentageValue) isThrottled() (loggerThrottled, trackerThrottled bool) { + loggerThrottled = p.logger < 0 || predictAnalyticsThrottle(p.logger) + + if loggerThrottled && p.logger >= 0 { + return true, true + } + + if p.tracker > 0 { + trackerThrottled = predictAnalyticsThrottle(p.tracker) + } + return +} + +type pubThrottling map[int]map[int]*percentageValue + +func newPubThrottling(defaultValue string) pubThrottling { + ant := make(pubThrottling) + ant.add(defaultValue) + return ant +} + +func (ant pubThrottling) add(value string) { + // config format: :::,:::,... + keys := strings.Split(value, keySeparator) + for _, key := range keys { + if key == "" { + continue + } + pubID, profileID, loggerPercentage, trackerPercentage, err := getKeyParts(key) + if err != nil { + continue + } + + if ant[pubID] == nil { + ant[pubID] = map[int]*percentageValue{} + } + + ant[pubID][profileID] = &percentageValue{ + logger: loggerPercentage, + tracker: trackerPercentage, + } + } +} + +func (ant pubThrottling) merge(source pubThrottling, replaceExisting bool) { + for pubID, profiles := range source { + for profileID, percentage := range profiles { + if ant[pubID] == nil { + ant[pubID] = map[int]*percentageValue{} + } + if replaceExisting || ant[pubID][profileID] == nil { + ant[pubID][profileID] = percentage + } + } + } +} + +func getKeyParts(key string) (int, int, int, int, error) { + var err error + var pubID, profileID, loggerPercentage, trackerPercentage int + + parts := strings.Split(key, keyPartSeparator) + if len(parts) != 4 { + return 0, 0, 0, 0, fmt.Errorf(errInvalidAnalyticsThrottlingKeyFormat, "LENGTH", key) + } + + if pubID, err = strconv.Atoi(parts[keyPartPubID]); err != nil || pubID <= 0 { + return 0, 0, 0, 0, fmt.Errorf(errInvalidAnalyticsThrottlingKeyFormat, "PUBID", key) + } + + if profileID, err = strconv.Atoi(parts[keyPartProfileID]); err != nil || profileID < 0 { + return 0, 0, 0, 0, fmt.Errorf(errInvalidAnalyticsThrottlingKeyFormat, "PROFILEID", key) + } + + if loggerPercentage, err = strconv.Atoi(parts[keyPartLoggerPercentage]); err != nil || loggerPercentage < -1 { + return 0, 0, 0, 0, fmt.Errorf(errInvalidAnalyticsThrottlingKeyFormat, "LOGGER_PERCENTAGE", key) + } + + if trackerPercentage, err = strconv.Atoi(parts[keyPartTrackerPercentage]); err != nil || trackerPercentage < 0 { + return 0, 0, 0, 0, fmt.Errorf(errInvalidAnalyticsThrottlingKeyFormat, "TRACKER_PERCENTAGE", key) + } + + return pubID, profileID, loggerPercentage, trackerPercentage, err +} + +type analyticsThrottle struct { + vault, db pubThrottling +} + +func (at *analyticsThrottle) getThrottlingPercentage(pubID, profileID int) *percentageValue { + if pubThrottling, ok := at.db[pubID]; ok { + if value, ok := pubThrottling[profileID]; ok { + return value + } + if value, ok := pubThrottling[allProfiles]; ok { + return value + } + } + return nil +} + +func (fe *feature) updateAnalyticsThrottling() { + if fe.publisherFeature == nil { + return + } + + ant := make(pubThrottling) + for _, feature := range fe.publisherFeature { + if val, ok := feature[models.FeatureAnalyticsThrottle]; ok && val.Enabled == 1 { + ant.add(val.Value) + } + } + + if len(ant) == 0 { + return + } + + //add vault settings to db + ant.merge(fe.ant.db, false) + + fe.Lock() + fe.ant.db = ant + fe.Unlock() +} + +var randInt = rand.Intn + +func predictAnalyticsThrottle(threshold int) bool { + return randInt(100) < threshold +} + +// IsAnalyticsTrackingThrottled returns throttling logger,tracker or not +func (fe *feature) IsAnalyticsTrackingThrottled(pubID, profileID int) (bool, bool) { + fe.RLocker().Lock() + throttlingPercentage := fe.ant.getThrottlingPercentage(pubID, profileID) + fe.RLocker().Unlock() + + if throttlingPercentage == nil { + return false, false + } + return throttlingPercentage.isThrottled() +} diff --git a/modules/pubmatic/openwrap/publisherfeature/analyticsthrottle_test.go b/modules/pubmatic/openwrap/publisherfeature/analyticsthrottle_test.go new file mode 100644 index 00000000000..87a08720e00 --- /dev/null +++ b/modules/pubmatic/openwrap/publisherfeature/analyticsthrottle_test.go @@ -0,0 +1,352 @@ +package publisherfeature + +import ( + "testing" + + "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" + "github.com/stretchr/testify/assert" +) + +func TestIsThrottled(t *testing.T) { + tests := []struct { + name string + percentage *percentageValue + randomNumbers []int /*inclusive random number 0-99*/ + expectedLogger bool + expectedTracker bool + }{ + { + name: "logger_tracker_100%_throttled", + percentage: &percentageValue{logger: 100, tracker: 100}, + randomNumbers: []int{99}, + expectedLogger: true, + expectedTracker: true, + }, + { + name: "both_throttled", + percentage: &percentageValue{logger: 50, tracker: 60}, + randomNumbers: []int{20, 20}, + expectedLogger: true, + expectedTracker: true, + }, + { + name: "logger_tracker_not_throttled", + percentage: &percentageValue{logger: 50, tracker: 0}, + randomNumbers: []int{70, 20}, + expectedLogger: false, + expectedTracker: false, + }, + { + name: "logger_not_throttled_tracker_throttled", + percentage: &percentageValue{logger: 50, tracker: 60}, + randomNumbers: []int{70, 20}, + expectedLogger: false, + expectedTracker: true, + }, + { + name: "logger_disabled_tracker_not_throttled", + percentage: &percentageValue{logger: -1, tracker: 50}, + randomNumbers: []int{70}, + expectedLogger: true, + expectedTracker: false, + }, + { + name: "logger_disabled_tracker_throttled", + percentage: &percentageValue{logger: -1, tracker: 50}, + randomNumbers: []int{20}, + expectedLogger: true, + expectedTracker: true, + }, + { + name: "logger_disabled_tracker_100%_throttled", + percentage: &percentageValue{logger: -1, tracker: 100}, + randomNumbers: []int{99}, + expectedLogger: true, + expectedTracker: true, + }, + { + name: "neither_throttled", + percentage: &percentageValue{logger: 0, tracker: 0}, + randomNumbers: []int{20, 20}, + expectedLogger: false, + expectedTracker: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + count := 0 + randInt = func(_ int) int { + value := test.randomNumbers[count] + count++ + return value + } + logger, tracker := test.percentage.isThrottled() + assert.Equal(t, test.expectedLogger, logger) + assert.Equal(t, test.expectedTracker, tracker) + }) + } +} + +func TestGetKeyParts(t *testing.T) { + type want struct { + expectedPubID int + expectedProfileID int + expectedLoggerPercent int + expectedTrackerPercent int + expectedError bool + } + tests := []struct { + name string + key string + want want + }{ + { + name: "ValidKey", + key: "123:456:50:60", + want: want{ + expectedPubID: 123, + expectedProfileID: 456, + expectedLoggerPercent: 50, + expectedTrackerPercent: 60, + expectedError: false, + }, + }, + { + name: "InvalidKeyFormat", + key: "invalid", + want: want{expectedError: true}, + }, + { + name: "InvalidPubID", + key: "abc:456:50:60", + want: want{expectedError: true}, + }, + { + name: "InvalidPubID_Negative", + key: "-1:456:50:60", + want: want{expectedError: true}, + }, + { + name: "InvalidProfileID", + key: "123:def:50:60", + want: want{expectedError: true}, + }, + { + name: "InvalidProfileID_Negative", + key: "123:-1:50:60", + want: want{expectedError: true}, + }, + { + name: "InvalidLoggerPercent", + key: "123:456:hij:60", + want: want{expectedError: true}, + }, + { + name: "InvalidLoggerPercent_Negative", + key: "123:456:-50:60", + want: want{expectedError: true}, + }, + { + name: "InvalidTrackerPercent", + key: "123:456:50:klm", + want: want{expectedError: true}, + }, + { + name: "InvalidTrackerPercent_Negative", + key: "123:456:50:-60", + want: want{expectedError: true}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + pubID, profileID, loggerPercent, trackerPercent, err := getKeyParts(test.key) + + assert.Equal(t, test.want.expectedPubID, pubID) + assert.Equal(t, test.want.expectedProfileID, profileID) + assert.Equal(t, test.want.expectedLoggerPercent, loggerPercent) + assert.Equal(t, test.want.expectedTrackerPercent, trackerPercent) + + if test.want.expectedError { + assert.NotNil(t, err) + return + } + }) + } +} + +func TestPubThrottlingAdd(t *testing.T) { + tests := []struct { + name string + value string + expected pubThrottling + }{ + { + name: "ValidValue", + value: "1:1:50:60,2:1:40:70", + expected: pubThrottling{1: {1: {logger: 50, tracker: 60}}, 2: {1: {logger: 40, tracker: 70}}}, + }, + { + name: "EmptyValue", + value: "", + expected: pubThrottling{}, + }, + { + name: "InvalidValue", + value: "invalid", + expected: pubThrottling{}, + }, + { + name: "MissingValues", + value: "1:1:50:60,:1:40:70", + expected: pubThrottling{1: {1: {logger: 50, tracker: 60}}}, + }, + { + name: "NegativeValues", + value: "-1:1:50:60,2:1:-40:70", + expected: pubThrottling{}, + }, + { + name: "DisabledLoggerAndEnabledTracker", + value: "1:1:-1:70", + expected: pubThrottling{1: {1: {logger: -1, tracker: 70}}}, + }, + { + name: "MultipleProfiles", + value: "1:1:50:60,1:2:40:70", + expected: pubThrottling{1: {1: {logger: 50, tracker: 60}, 2: {logger: 40, tracker: 70}}}, + }, + { + name: "DuplicateEntries", + value: "1:1:50:60,1:1:40:70", + expected: pubThrottling{1: {1: {logger: 40, tracker: 70}}}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual := newPubThrottling(test.value) + assert.Equal(t, test.expected, actual) + }) + } +} + +func TestMerge(t *testing.T) { + tests := []struct { + name string + ant pubThrottling + source pubThrottling + replaceExisting bool + expected pubThrottling + }{ + { + name: "MergeWithReplaceExistingTrue", + ant: pubThrottling{ + 1: {1: {logger: 50, tracker: 60}}, + }, + source: pubThrottling{ + 1: {1: {logger: 70, tracker: 80}}, + 2: {2: {logger: 90, tracker: 100}}, + }, + replaceExisting: true, + expected: pubThrottling{ + 1: {1: {logger: 70, tracker: 80}}, + 2: {2: {logger: 90, tracker: 100}}, + }, + }, + { + name: "MergeWithReplaceExistingFalse", + ant: pubThrottling{ + 1: {1: {logger: 50, tracker: 60}}, + }, + source: pubThrottling{ + 1: {1: {logger: 70, tracker: 80}}, + 2: {2: {logger: 90, tracker: 100}}, + }, + replaceExisting: false, + expected: pubThrottling{ + 1: {1: {logger: 50, tracker: 60}}, + 2: {2: {logger: 90, tracker: 100}}, + }, + }, + // Add more test cases as needed + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ant.merge(test.source, test.replaceExisting) + assert.Equal(t, test.expected, test.ant) + }) + } +} + +func TestUpdateAnalyticsThrottling(t *testing.T) { + tests := []struct { + name string + feature *feature + expectedAnt pubThrottling + }{ + { + name: "NilPublisherFeature", + feature: &feature{}, + expectedAnt: nil, + }, + { + name: "WithPublisherFeature", + feature: &feature{ + publisherFeature: map[int]map[int]models.FeatureData{ + 1: { + models.FeatureAnalyticsThrottle: {Enabled: 1, Value: "1:1:50:60"}, + }, + }, + }, + expectedAnt: pubThrottling{ + 1: {1: {logger: 50, tracker: 60}}, + }, + }, + { + name: "EmptyAntDB", + feature: &feature{ + publisherFeature: map[int]map[int]models.FeatureData{ + 1: { + models.FeatureAnalyticsThrottle: {Enabled: 1, Value: "1:1:50:60"}, + }, + }, + }, + expectedAnt: pubThrottling{ + 1: {1: {logger: 50, tracker: 60}}, + }, + }, + { + name: "ExistingAntDB", + feature: &feature{ + ant: analyticsThrottle{ + vault: pubThrottling{ + 1: {1: {logger: 30, tracker: 40}}, + }, + db: pubThrottling{ + 1: {1: {logger: 30, tracker: 40}, 2: {logger: 30, tracker: 40}}, + 2: {1: {logger: 30, tracker: 40}}, + }, + }, + publisherFeature: map[int]map[int]models.FeatureData{ + 1: { + models.FeatureAnalyticsThrottle: {Enabled: 1, Value: "1:1:50:60"}, + }, + }, + }, + expectedAnt: pubThrottling{ + 1: {1: {logger: 50, tracker: 60}, 2: {logger: 30, tracker: 40}}, + 2: {1: {logger: 30, tracker: 40}}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.feature.updateAnalyticsThrottling() + assert.Equal(t, test.expectedAnt, test.feature.ant.db) + }) + } +} diff --git a/modules/pubmatic/openwrap/publisherfeature/feature.go b/modules/pubmatic/openwrap/publisherfeature/feature.go index 8440f55b036..9882418e977 100644 --- a/modules/pubmatic/openwrap/publisherfeature/feature.go +++ b/modules/pubmatic/openwrap/publisherfeature/feature.go @@ -4,4 +4,5 @@ type Feature interface { IsFscApplicable(pubId int, seat string, dspId int) bool IsAmpMultiformatEnabled(pubId int) bool IsTBFFeatureEnabled(pubid int, profid int) bool + IsAnalyticsTrackingThrottled(pubID, profileID int) (bool, bool) } diff --git a/modules/pubmatic/openwrap/publisherfeature/mock/mock.go b/modules/pubmatic/openwrap/publisherfeature/mock/mock.go index d8930b19e56..575263d81bf 100644 --- a/modules/pubmatic/openwrap/publisherfeature/mock/mock.go +++ b/modules/pubmatic/openwrap/publisherfeature/mock/mock.go @@ -1,38 +1,39 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/PubMatic-OpenWrap/prebid-server/modules/pubmatic/openwrap/publisherfeature (interfaces: Feature) +// Source: github.com/PubMatic-OpenWrap/prebid-server/v2/modules/pubmatic/openwrap/publisherfeature (interfaces: Feature) // Package mock_publisherfeature is a generated GoMock package. package mock_publisherfeature import ( - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" ) -// MockFeature is a mock of Feature interface +// MockFeature is a mock of Feature interface. type MockFeature struct { ctrl *gomock.Controller recorder *MockFeatureMockRecorder } -// MockFeatureMockRecorder is the mock recorder for MockFeature +// MockFeatureMockRecorder is the mock recorder for MockFeature. type MockFeatureMockRecorder struct { mock *MockFeature } -// NewMockFeature creates a new mock instance +// NewMockFeature creates a new mock instance. func NewMockFeature(ctrl *gomock.Controller) *MockFeature { mock := &MockFeature{ctrl: ctrl} mock.recorder = &MockFeatureMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockFeature) EXPECT() *MockFeatureMockRecorder { return m.recorder } -// IsAmpMultiformatEnabled mocks base method +// IsAmpMultiformatEnabled mocks base method. func (m *MockFeature) IsAmpMultiformatEnabled(arg0 int) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsAmpMultiformatEnabled", arg0) @@ -40,13 +41,28 @@ func (m *MockFeature) IsAmpMultiformatEnabled(arg0 int) bool { return ret0 } -// IsAmpMultiformatEnabled indicates an expected call of IsAmpMultiformatEnabled +// IsAmpMultiformatEnabled indicates an expected call of IsAmpMultiformatEnabled. func (mr *MockFeatureMockRecorder) IsAmpMultiformatEnabled(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAmpMultiformatEnabled", reflect.TypeOf((*MockFeature)(nil).IsAmpMultiformatEnabled), arg0) } -// IsFscApplicable mocks base method +// IsAnalyticsTrackingThrottled mocks base method. +func (m *MockFeature) IsAnalyticsTrackingThrottled(arg0, arg1 int) (bool, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsAnalyticsTrackingThrottled", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// IsAnalyticsTrackingThrottled indicates an expected call of IsAnalyticsTrackingThrottled. +func (mr *MockFeatureMockRecorder) IsAnalyticsTrackingThrottled(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAnalyticsTrackingThrottled", reflect.TypeOf((*MockFeature)(nil).IsAnalyticsTrackingThrottled), arg0, arg1) +} + +// IsFscApplicable mocks base method. func (m *MockFeature) IsFscApplicable(arg0 int, arg1 string, arg2 int) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsFscApplicable", arg0, arg1, arg2) @@ -54,13 +70,13 @@ func (m *MockFeature) IsFscApplicable(arg0 int, arg1 string, arg2 int) bool { return ret0 } -// IsFscApplicable indicates an expected call of IsFscApplicable +// IsFscApplicable indicates an expected call of IsFscApplicable. func (mr *MockFeatureMockRecorder) IsFscApplicable(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFscApplicable", reflect.TypeOf((*MockFeature)(nil).IsFscApplicable), arg0, arg1, arg2) } -// IsTBFFeatureEnabled mocks base method +// IsTBFFeatureEnabled mocks base method. func (m *MockFeature) IsTBFFeatureEnabled(arg0, arg1 int) bool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "IsTBFFeatureEnabled", arg0, arg1) @@ -68,7 +84,7 @@ func (m *MockFeature) IsTBFFeatureEnabled(arg0, arg1 int) bool { return ret0 } -// IsTBFFeatureEnabled indicates an expected call of IsTBFFeatureEnabled +// IsTBFFeatureEnabled indicates an expected call of IsTBFFeatureEnabled. func (mr *MockFeatureMockRecorder) IsTBFFeatureEnabled(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTBFFeatureEnabled", reflect.TypeOf((*MockFeature)(nil).IsTBFFeatureEnabled), arg0, arg1) diff --git a/modules/pubmatic/openwrap/publisherfeature/reloader.go b/modules/pubmatic/openwrap/publisherfeature/reloader.go index 34e384ca999..09ac7cf31c8 100644 --- a/modules/pubmatic/openwrap/publisherfeature/reloader.go +++ b/modules/pubmatic/openwrap/publisherfeature/reloader.go @@ -9,6 +9,12 @@ import ( "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" ) +type Config struct { + Cache cache.Cache + DefaultExpiry int + AnalyticsThrottleList string +} + type feature struct { cache cache.Cache serviceStop chan struct{} @@ -17,18 +23,19 @@ type feature struct { publisherFeature map[int]map[int]models.FeatureData fsc fsc tbf tbf + ant analyticsThrottle ampMultiformat ampMultiformat } var fe *feature var fOnce sync.Once -func New(c cache.Cache, defaultExpiry int) *feature { +func New(config Config) *feature { fOnce.Do(func() { fe = &feature{ - cache: c, + cache: config.Cache, serviceStop: make(chan struct{}), - defaultExpiry: defaultExpiry, + defaultExpiry: config.DefaultExpiry, publisherFeature: make(map[int]map[int]models.FeatureData), fsc: fsc{ disabledPublishers: make(map[int]struct{}), @@ -40,6 +47,10 @@ func New(c cache.Cache, defaultExpiry int) *feature { ampMultiformat: ampMultiformat{ enabledPublishers: make(map[int]struct{}), }, + ant: analyticsThrottle{ + vault: newPubThrottling(config.AnalyticsThrottleList), + db: newPubThrottling(config.AnalyticsThrottleList), + }, } }) return fe @@ -93,6 +104,7 @@ func (fe *feature) updateFeatureConfigMaps() { fe.updateTBFConfigMap() fe.updateAmpMutiformatEnabledPublishers() + fe.updateAnalyticsThrottling() if err != nil { glog.Error(err.Error()) diff --git a/modules/pubmatic/openwrap/publisherfeature/reloader_test.go b/modules/pubmatic/openwrap/publisherfeature/reloader_test.go index f733c15e8d3..138f5cccccb 100644 --- a/modules/pubmatic/openwrap/publisherfeature/reloader_test.go +++ b/modules/pubmatic/openwrap/publisherfeature/reloader_test.go @@ -13,25 +13,22 @@ import ( ) func TestNew(t *testing.T) { - type args struct { - c cache.Cache - defaultExpiry int - } tests := []struct { name string - args args + args Config }{ { name: "test", - args: args{ - c: nil, - defaultExpiry: 0, + args: Config{ + Cache: nil, + DefaultExpiry: 0, + AnalyticsThrottleList: "", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := New(tt.args.c, tt.args.defaultExpiry) + got := New(tt.args) assert.Equal(t, fe, got) }) } diff --git a/modules/pubmatic/openwrap/targeting.go b/modules/pubmatic/openwrap/targeting.go index 757827990c6..64138eb8a39 100644 --- a/modules/pubmatic/openwrap/targeting.go +++ b/modules/pubmatic/openwrap/targeting.go @@ -107,7 +107,7 @@ func (m OpenWrap) addPWTTargetingForBid(rctx models.RequestCtx, bidResponse *ope if rctx.SendAllBids { bidCtx.Winner = 1 } - if m.featureConfig.IsFscApplicable(rctx.PubID, seatBid.Seat, bidCtx.DspId) { + if m.pubFeatures.IsFscApplicable(rctx.PubID, seatBid.Seat, bidCtx.DspId) { bidCtx.Fsc = 1 } } else if !rctx.SendAllBids { diff --git a/modules/pubmatic/openwrap/tracker/inject.go b/modules/pubmatic/openwrap/tracker/inject.go index 391cdd113a3..47d63afd41c 100644 --- a/modules/pubmatic/openwrap/tracker/inject.go +++ b/modules/pubmatic/openwrap/tracker/inject.go @@ -13,6 +13,10 @@ import ( ) func InjectTrackers(rctx models.RequestCtx, bidResponse *openrtb2.BidResponse) (*openrtb2.BidResponse, error) { + if rctx.TrackerDisabled { + return bidResponse, nil + } + var errs error for i, seatBid := range bidResponse.SeatBid { for j, bid := range seatBid.Bid { diff --git a/modules/pubmatic/openwrap/tracker/inject_test.go b/modules/pubmatic/openwrap/tracker/inject_test.go index 675c720655a..0738228b7d5 100644 --- a/modules/pubmatic/openwrap/tracker/inject_test.go +++ b/modules/pubmatic/openwrap/tracker/inject_test.go @@ -37,6 +37,40 @@ func TestInjectTrackers(t *testing.T) { want: &openrtb2.BidResponse{}, wantErr: false, }, + { + name: "tracker_disabled", + args: args{ + rctx: models.RequestCtx{ + Platform: "video", + TrackerDisabled: true, + }, + bidResponse: &openrtb2.BidResponse{ + SeatBid: []openrtb2.SeatBid{ + { + Bid: []openrtb2.Bid{ + { + ID: "12345", + AdM: `creative`, + }, + }, + }, + }, + }, + }, + want: &openrtb2.BidResponse{ + SeatBid: []openrtb2.SeatBid{ + { + Bid: []openrtb2.Bid{ + { + ID: "12345", + AdM: `creative`, + }, + }, + }, + }, + }, + wantErr: false, + }, { name: "tracker_params_missing", args: args{ diff --git a/modules/pubmatic/openwrap/tracker/tracker.go b/modules/pubmatic/openwrap/tracker/tracker.go index db1ddbf9e44..4a22bc9969a 100644 --- a/modules/pubmatic/openwrap/tracker/tracker.go +++ b/modules/pubmatic/openwrap/tracker/tracker.go @@ -9,6 +9,10 @@ import ( ) func GetTrackerInfo(rCtx models.RequestCtx, responseExt openrtb_ext.ExtBidResponse) string { + if rCtx.TrackerDisabled { + return "" + } + floorsDetails := models.GetFloorsDetails(responseExt) tracker := models.Tracker{ PubID: rCtx.PubID, diff --git a/modules/pubmatic/openwrap/tracker/tracker_test.go b/modules/pubmatic/openwrap/tracker/tracker_test.go index c20154037a7..57053cdf47e 100644 --- a/modules/pubmatic/openwrap/tracker/tracker_test.go +++ b/modules/pubmatic/openwrap/tracker/tracker_test.go @@ -23,6 +23,16 @@ func TestGetTrackerInfo(t *testing.T) { args args want string }{ + { + name: "tracker_disabled", + args: args{ + rCtx: models.RequestCtx{ + TrackerDisabled: true, + }, + responseExt: openrtb_ext.ExtBidResponse{}, + }, + want: "", + }, { name: "all_tracker_info_without_floors", args: args{ diff --git a/openrtb_ext/adpod.go b/openrtb_ext/openwrap.go similarity index 98% rename from openrtb_ext/adpod.go rename to openrtb_ext/openwrap.go index ed3fef3ba09..47670d30cd8 100644 --- a/openrtb_ext/adpod.go +++ b/openrtb_ext/openwrap.go @@ -39,6 +39,12 @@ const ( OWRoundupVideoAdDurationMatching OWVideoAdDurationMatchingPolicy = `roundup` ) +type ExtOWRequestPrebid struct { + Transparency *TransparencyExt `json:"transparency,omitempty"` + KeyVal map[string]interface{} `json:"keyval,omitempty"` + TrackerDisabled bool `json:"tracker_disabled,omitempty"` +} + // ExtCTVBid defines the contract for bidresponse.seatbid.bid[i].ext type ExtOWBid struct { ExtBid diff --git a/openrtb_ext/adpod_test.go b/openrtb_ext/openwrap_test.go similarity index 100% rename from openrtb_ext/adpod_test.go rename to openrtb_ext/openwrap_test.go diff --git a/openrtb_ext/request.go b/openrtb_ext/request.go index 2c5ac8a3650..b0903cc2345 100644 --- a/openrtb_ext/request.go +++ b/openrtb_ext/request.go @@ -91,8 +91,7 @@ type ExtRequestPrebid struct { // any other value or an empty string disables trace output at all. Trace string `json:"trace,omitempty"` - Transparency *TransparencyExt `json:"transparency,omitempty"` - KeyVal map[string]interface{} `json:"keyval,omitempty"` + ExtOWRequestPrebid } type AdServerTarget struct { From cb8ef8afabb57e31a6f2cfcfe3d35d16af5c1769 Mon Sep 17 00:00:00 2001 From: Nikhil Vaidya <102963966+pm-nikhil-vaidya@users.noreply.github.com> Date: Thu, 2 May 2024 11:42:06 +0530 Subject: [PATCH 2/2] OTT-1726 enable analytics throttling for amp and modules 2.5 endpoint (#779) Co-authored-by: Viral Vala --- endpoints/openrtb2/auction_ow.go | 4 +- .../pubmatic/openwrap/beforevalidationhook.go | 13 +++++++ .../openwrap/beforevalidationhook_test.go | 33 +++++++++++----- .../openwrap/database/mysql/adunit_config.go | 7 +++- .../database/mysql/adunit_config_test.go | 7 ++++ .../database/mysql/fullscreenclickability.go | 7 +++- .../mysql/fullscreenclickability_test.go | 2 + .../database/mysql/partner_config_test.go | 2 + .../database/mysql/publisher_feature.go | 7 +++- .../database/mysql/publisher_feature_test.go | 3 ++ .../openwrap/database/mysql/slot_mapping.go | 8 +++- .../database/mysql/slot_mapping_test.go | 2 + .../openwrap/database/mysql/vasttags.go | 15 +++----- .../openwrap/database/mysql/vasttags_test.go | 2 + modules/pubmatic/openwrap/entrypointhook.go | 2 - .../pubmatic/openwrap/entrypointhook_test.go | 38 ++++++------------- modules/pubmatic/openwrap/models/constants.go | 5 +++ 17 files changed, 104 insertions(+), 53 deletions(-) diff --git a/endpoints/openrtb2/auction_ow.go b/endpoints/openrtb2/auction_ow.go index f9678dfeda0..ce91e1ec5d3 100644 --- a/endpoints/openrtb2/auction_ow.go +++ b/endpoints/openrtb2/auction_ow.go @@ -60,7 +60,7 @@ func UpdateResponseExtOW(bidResponse *openrtb2.BidResponse, ao analytics.Auction } } - if rCtx.LogInfoFlag == 1 { + if rCtx.LogInfoFlag == 1 && !rCtx.LoggerDisabled { extBidResponse.OwLogInfo.Logger, _ = pubmatic.GetLogAuctionObjectAsURL(ao, rCtx, true, true) } @@ -72,7 +72,7 @@ func UpdateResponseExtOW(bidResponse *openrtb2.BidResponse, ao analytics.Auction // extBidResponse.Prebid.SeatNonBid = seatNonBids // } - if rCtx.Debug { + if rCtx.Debug && !rCtx.LoggerDisabled { extBidResponse.OwLogger, _ = pubmatic.GetLogAuctionObjectAsURL(ao, rCtx, false, true) } diff --git a/modules/pubmatic/openwrap/beforevalidationhook.go b/modules/pubmatic/openwrap/beforevalidationhook.go index 5cadcb6e8d0..095850b2e50 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook.go +++ b/modules/pubmatic/openwrap/beforevalidationhook.go @@ -105,6 +105,7 @@ func (m OpenWrap) handleBeforeValidationHook( rCtx.NewReqExt = requestExt rCtx.CustomDimensions = customdimensions.GetCustomDimensions(requestExt.Prebid.BidderParams) rCtx.ReturnAllBidStatus = requestExt.Prebid.ReturnAllBidStatus + m.setAnanlyticsFlags(&rCtx) // TODO: verify preference of request.test vs queryParam test ++ this check is only for the CTV requests if payload.BidRequest.Test != 0 { @@ -931,6 +932,18 @@ func getTagID(imp openrtb2.Imp, impExt *models.ImpExtension) string { return impExt.Data.PbAdslot } +func (m OpenWrap) setAnanlyticsFlags(rCtx *models.RequestCtx) { + rCtx.LoggerDisabled, rCtx.TrackerDisabled = m.pubFeatures.IsAnalyticsTrackingThrottled(rCtx.PubID, rCtx.ProfileID) + + if rCtx.LoggerDisabled { + rCtx.MetricsEngine.RecordAnalyticsTrackingThrottled(strconv.Itoa(rCtx.PubID), strconv.Itoa(rCtx.ProfileID), models.AnanlyticsThrottlingLoggerType) + } + + if rCtx.TrackerDisabled { + rCtx.MetricsEngine.RecordAnalyticsTrackingThrottled(strconv.Itoa(rCtx.PubID), strconv.Itoa(rCtx.ProfileID), models.AnanlyticsThrottlingTrackerType) + } +} + func updateImpVideoWithVideoConfig(imp *openrtb2.Imp, configObjInVideoConfig *modelsAdunitConfig.VideoConfig) { if len(imp.Video.MIMEs) == 0 { diff --git a/modules/pubmatic/openwrap/beforevalidationhook_test.go b/modules/pubmatic/openwrap/beforevalidationhook_test.go index 057ef5d0802..d5ac47da6a1 100644 --- a/modules/pubmatic/openwrap/beforevalidationhook_test.go +++ b/modules/pubmatic/openwrap/beforevalidationhook_test.go @@ -2312,7 +2312,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPublisherInvalidProfileRequests(rctx.Endpoint, "5890", rctx.ProfileIDStr) mockEngine.EXPECT().RecordPublisherInvalidProfileImpressions("5890", rctx.ProfileIDStr, gomock.Any()) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) - + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2345,7 +2345,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPublisherInvalidProfileRequests(rctx.Endpoint, "5890", rctx.ProfileIDStr) mockEngine.EXPECT().RecordPublisherInvalidProfileImpressions("5890", rctx.ProfileIDStr, gomock.Any()) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) - + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2390,7 +2390,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPublisherInvalidProfileRequests(rctx.Endpoint, "5890", rctx.ProfileIDStr) mockEngine.EXPECT().RecordPublisherInvalidProfileImpressions("5890", rctx.ProfileIDStr, gomock.Any()) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) - + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2436,6 +2436,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.AllPartnerThrottled)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2481,6 +2482,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.InvalidImpressionTagID)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2530,6 +2532,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.InvalidImpressionTagID)) mockEngine.EXPECT().RecordPublisherRequests(models.EndpointWebS2S, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2575,6 +2578,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.InternalError)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2664,6 +2668,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordImpDisabledViaConfigStats(models.ImpTypeVideo, "5890", "1234") mockEngine.EXPECT().RecordImpDisabledViaConfigStats(models.ImpTypeBanner, "5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2767,6 +2772,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordImpDisabledViaConfigStats(models.ImpTypeVideo, "5890", "1234") mockEngine.EXPECT().RecordImpDisabledViaConfigStats(models.ImpTypeBanner, "5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: false, @@ -2844,7 +2850,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.ServerSidePartnerNotConfigured)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) - + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: true, @@ -2955,6 +2961,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "dm-alias") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: false, @@ -3046,6 +3053,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: false, @@ -3206,6 +3214,7 @@ func TestOpenWrapHandleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats("amp", "5890", "appnexus") mockFeature.EXPECT().IsAmpMultiformatEnabled(5890).Return(true) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: hookstage.HookResult[hookstage.BeforeValidationRequestPayload]{ Reject: false, @@ -3459,11 +3468,11 @@ func TestVASTUnwrap_handleBeforeValidationHook(t *testing.T) { }, }, nil) mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{}) - mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3520,11 +3529,11 @@ func TestVASTUnwrap_handleBeforeValidationHook(t *testing.T) { }, }, nil) mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{}) - mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3586,11 +3595,11 @@ func TestVASTUnwrap_handleBeforeValidationHook(t *testing.T) { }, }, nil) mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{}) - mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3653,11 +3662,11 @@ func TestVASTUnwrap_handleBeforeValidationHook(t *testing.T) { }, }, nil) mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{}) - mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3715,11 +3724,11 @@ func TestVASTUnwrap_handleBeforeValidationHook(t *testing.T) { }, }, nil) mockCache.EXPECT().GetAdunitConfigFromCache(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&adunitconfig.AdUnitConfig{}) - mockEngine.EXPECT().RecordPlatformPublisherPartnerReqStats(rctx.Platform, "5890", "appnexus") mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockEngine.EXPECT().RecordPublisherProfileRequests("5890", "1234") mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3821,6 +3830,7 @@ func TestImpBidCtx_handleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPublisherInvalidProfileRequests(rctx.Endpoint, "5890", rctx.ProfileIDStr) mockEngine.EXPECT().RecordPublisherInvalidProfileImpressions("5890", rctx.ProfileIDStr, gomock.Any()) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3873,7 +3883,7 @@ func TestImpBidCtx_handleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordPublisherInvalidProfileRequests(rctx.Endpoint, "5890", rctx.ProfileIDStr) mockEngine.EXPECT().RecordPublisherInvalidProfileImpressions("5890", rctx.ProfileIDStr, gomock.Any()) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) - + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -3927,6 +3937,7 @@ func TestImpBidCtx_handleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.AllPartnerThrottled)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ error: false, @@ -3980,6 +3991,7 @@ func TestImpBidCtx_handleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.InvalidImpressionTagID)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ @@ -4025,6 +4037,7 @@ func TestImpBidCtx_handleBeforeValidationHook(t *testing.T) { mockEngine.EXPECT().RecordNobidErrPrebidServerRequests("5890", int(nbr.InternalError)) mockEngine.EXPECT().RecordPublisherRequests(rctx.Endpoint, "5890", rctx.Platform) mockFeature.EXPECT().IsTBFFeatureEnabled(gomock.Any(), gomock.Any()).Return(false) + mockFeature.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()).Return(false, false) }, want: want{ rctx: &models.RequestCtx{ diff --git a/modules/pubmatic/openwrap/database/mysql/adunit_config.go b/modules/pubmatic/openwrap/database/mysql/adunit_config.go index 98fbf8dd0a2..d3a27c2edaa 100644 --- a/modules/pubmatic/openwrap/database/mysql/adunit_config.go +++ b/modules/pubmatic/openwrap/database/mysql/adunit_config.go @@ -1,10 +1,12 @@ package mysql import ( + "context" "database/sql" "encoding/json" "strconv" "strings" + "time" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models/adunitconfig" @@ -19,8 +21,11 @@ func (db *mySqlDB) GetAdunitConfig(profileID, displayVersion int) (*adunitconfig adunitConfigQuery = strings.Replace(adunitConfigQuery, profileIdKey, strconv.Itoa(profileID), -1) adunitConfigQuery = strings.Replace(adunitConfigQuery, displayVersionKey, strconv.Itoa(displayVersion), -1) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*time.Duration(db.cfg.MaxDbContextTimeout))) + defer cancel() + var adunitConfigJSON string - err := db.conn.QueryRow(adunitConfigQuery).Scan(&adunitConfigJSON) + err := db.conn.QueryRowContext(ctx, adunitConfigQuery).Scan(&adunitConfigJSON) if err != nil { if err == sql.ErrNoRows { return nil, nil diff --git a/modules/pubmatic/openwrap/database/mysql/adunit_config_test.go b/modules/pubmatic/openwrap/database/mysql/adunit_config_test.go index 75968ed56b0..2e370c385f0 100644 --- a/modules/pubmatic/openwrap/database/mysql/adunit_config_test.go +++ b/modules/pubmatic/openwrap/database/mysql/adunit_config_test.go @@ -47,6 +47,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigForLiveVersion: "^SELECT (.+) FROM wrapper_media_config (.+) LIVE", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -72,6 +73,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigForLiveVersion: "^SELECT (.+) FROM wrapper_media_config (.+) LIVE", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -102,6 +104,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigQuery: "^SELECT (.+) FROM wrapper_media_config (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -132,6 +135,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigForLiveVersion: "^SELECT (.+) FROM wrapper_media_config (.+) LIVE", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -157,6 +161,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigQuery: "^SELECT (.+) FROM wrapper_media_config (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -187,6 +192,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigQuery: "^SELECT (.+) FROM wrapper_media_config (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -218,6 +224,7 @@ func Test_mySqlDB_GetAdunitConfig(t *testing.T) { Queries: config.Queries{ GetAdunitConfigQuery: "^SELECT (.+) FROM wrapper_media_config (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ diff --git a/modules/pubmatic/openwrap/database/mysql/fullscreenclickability.go b/modules/pubmatic/openwrap/database/mysql/fullscreenclickability.go index f0a1e8ecfb6..05999d60f67 100644 --- a/modules/pubmatic/openwrap/database/mysql/fullscreenclickability.go +++ b/modules/pubmatic/openwrap/database/mysql/fullscreenclickability.go @@ -1,13 +1,18 @@ package mysql import ( + "context" "strconv" + "time" "github.com/golang/glog" ) func (db *mySqlDB) GetFSCThresholdPerDSP() (map[int]int, error) { - rows, err := db.conn.Query(db.cfg.Queries.GetAllDspFscPcntQuery) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*time.Duration(db.cfg.MaxDbContextTimeout))) + defer cancel() + + rows, err := db.conn.QueryContext(ctx, db.cfg.Queries.GetAllDspFscPcntQuery) if err != nil { return nil, err } diff --git a/modules/pubmatic/openwrap/database/mysql/fullscreenclickability_test.go b/modules/pubmatic/openwrap/database/mysql/fullscreenclickability_test.go index c1aca4b29ee..811494e6f23 100644 --- a/modules/pubmatic/openwrap/database/mysql/fullscreenclickability_test.go +++ b/modules/pubmatic/openwrap/database/mysql/fullscreenclickability_test.go @@ -40,6 +40,7 @@ func Test_mySqlDB_GetFSCThresholdPerDSP(t *testing.T) { Queries: config.Queries{ GetAllDspFscPcntQuery: "^SELECT (.+) FROM wrapper_feature_dsp_mapping (.+)", }, + MaxDbContextTimeout: 1000, }, }, want: map[int]int{}, @@ -61,6 +62,7 @@ func Test_mySqlDB_GetFSCThresholdPerDSP(t *testing.T) { Queries: config.Queries{ GetAllDspFscPcntQuery: "^SELECT (.+) FROM wrapper_feature_dsp_mapping (.+)", }, + MaxDbContextTimeout: 1000, }, }, want: map[int]int{ diff --git a/modules/pubmatic/openwrap/database/mysql/partner_config_test.go b/modules/pubmatic/openwrap/database/mysql/partner_config_test.go index 4a81171d7b2..ea89b8b2116 100644 --- a/modules/pubmatic/openwrap/database/mysql/partner_config_test.go +++ b/modules/pubmatic/openwrap/database/mysql/partner_config_test.go @@ -34,6 +34,7 @@ func Test_mySqlDB_GetActivePartnerConfigurations(t *testing.T) { Queries: config.Queries{ LiveVersionInnerQuery: "^SELECT (.+) FROM wrapper_version (.+) LIVE", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -63,6 +64,7 @@ func Test_mySqlDB_GetActivePartnerConfigurations(t *testing.T) { Queries: config.Queries{ LiveVersionInnerQuery: "^SELECT (.+) FROM wrapper_version (.+) LIVE", }, + MaxDbContextTimeout: 1000, }, }, args: args{ diff --git a/modules/pubmatic/openwrap/database/mysql/publisher_feature.go b/modules/pubmatic/openwrap/database/mysql/publisher_feature.go index 66fbc3fbc52..a5c20f9568e 100644 --- a/modules/pubmatic/openwrap/database/mysql/publisher_feature.go +++ b/modules/pubmatic/openwrap/database/mysql/publisher_feature.go @@ -1,14 +1,19 @@ package mysql import ( + "context" "database/sql" + "time" "github.com/golang/glog" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" ) func (db *mySqlDB) GetPublisherFeatureMap() (map[int]map[int]models.FeatureData, error) { - rows, err := db.conn.Query(db.cfg.Queries.GetPublisherFeatureMapQuery) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*time.Duration(db.cfg.MaxDbContextTimeout))) + defer cancel() + + rows, err := db.conn.QueryContext(ctx, db.cfg.Queries.GetPublisherFeatureMapQuery) if err != nil { return nil, err } diff --git a/modules/pubmatic/openwrap/database/mysql/publisher_feature_test.go b/modules/pubmatic/openwrap/database/mysql/publisher_feature_test.go index 4892e0f49de..fa13d09e01f 100644 --- a/modules/pubmatic/openwrap/database/mysql/publisher_feature_test.go +++ b/modules/pubmatic/openwrap/database/mysql/publisher_feature_test.go @@ -41,6 +41,7 @@ func Test_mySqlDB_GetPublisherFeatureMap(t *testing.T) { Queries: config.Queries{ GetPublisherFeatureMapQuery: "^SELECT (.+) FROM test_wrapper_table (.+)", }, + MaxDbContextTimeout: 1000, }, }, want: map[int]map[int]models.FeatureData{}, @@ -62,6 +63,7 @@ func Test_mySqlDB_GetPublisherFeatureMap(t *testing.T) { Queries: config.Queries{ GetPublisherFeatureMapQuery: "^SELECT (.+) FROM test_wrapper_table (.+)", }, + MaxDbContextTimeout: 1000, }, }, want: map[int]map[int]models.FeatureData{ @@ -99,6 +101,7 @@ func Test_mySqlDB_GetPublisherFeatureMap(t *testing.T) { Queries: config.Queries{ GetPublisherFeatureMapQuery: "^SELECT (.+) FROM test_wrapper_table (.+)", }, + MaxDbContextTimeout: 1000, }, }, want: map[int]map[int]models.FeatureData{}, diff --git a/modules/pubmatic/openwrap/database/mysql/slot_mapping.go b/modules/pubmatic/openwrap/database/mysql/slot_mapping.go index 11135599a1f..0cbf4f26a09 100644 --- a/modules/pubmatic/openwrap/database/mysql/slot_mapping.go +++ b/modules/pubmatic/openwrap/database/mysql/slot_mapping.go @@ -1,10 +1,12 @@ package mysql import ( + "context" "errors" "fmt" "strconv" "strings" + "time" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" ) @@ -14,7 +16,11 @@ func (db *mySqlDB) GetPublisherSlotNameHash(pubID int) (map[string]string, error nameHashMap := make(map[string]string) query := db.formSlotNameHashQuery(pubID) - rows, err := db.conn.Query(query) + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*time.Duration(db.cfg.MaxDbContextTimeout))) + defer cancel() + + rows, err := db.conn.QueryContext(ctx, query) if err != nil { return nameHashMap, err } diff --git a/modules/pubmatic/openwrap/database/mysql/slot_mapping_test.go b/modules/pubmatic/openwrap/database/mysql/slot_mapping_test.go index 313714d7c9d..68c48566481 100644 --- a/modules/pubmatic/openwrap/database/mysql/slot_mapping_test.go +++ b/modules/pubmatic/openwrap/database/mysql/slot_mapping_test.go @@ -45,6 +45,7 @@ func Test_mySqlDB_GetPublisherSlotNameHash(t *testing.T) { Queries: config.Queries{ GetSlotNameHash: "^SELECT (.+) FROM wrapper_publisher_slot (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -77,6 +78,7 @@ func Test_mySqlDB_GetPublisherSlotNameHash(t *testing.T) { Queries: config.Queries{ GetSlotNameHash: "^SELECT (.+) FROM wrapper_publisher_slot (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ diff --git a/modules/pubmatic/openwrap/database/mysql/vasttags.go b/modules/pubmatic/openwrap/database/mysql/vasttags.go index 6b036ac00a5..380bcdada32 100644 --- a/modules/pubmatic/openwrap/database/mysql/vasttags.go +++ b/modules/pubmatic/openwrap/database/mysql/vasttags.go @@ -1,24 +1,21 @@ package mysql import ( + "context" "fmt" + "time" "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/models" ) // GetPublisherVASTTags - Method to get vast tags associated with publisher id from giym DB func (db *mySqlDB) GetPublisherVASTTags(pubID int) (models.PublisherVASTTags, error) { - - /* - //TOOD:VIRAL Remove Hook once UI/API changes are in place - if out := vastTagHookPublisherVASTTags(rtbReqId, pubID); nil != out { - return out, nil - } - */ - getActiveVASTTagsQuery := fmt.Sprintf(db.cfg.Queries.GetPublisherVASTTagsQuery, pubID) - rows, err := db.conn.Query(getActiveVASTTagsQuery) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*time.Duration(db.cfg.MaxDbContextTimeout))) + defer cancel() + + rows, err := db.conn.QueryContext(ctx, getActiveVASTTagsQuery) if err != nil { return nil, err } diff --git a/modules/pubmatic/openwrap/database/mysql/vasttags_test.go b/modules/pubmatic/openwrap/database/mysql/vasttags_test.go index 7e8b183d951..1709cd9ff93 100644 --- a/modules/pubmatic/openwrap/database/mysql/vasttags_test.go +++ b/modules/pubmatic/openwrap/database/mysql/vasttags_test.go @@ -45,6 +45,7 @@ func Test_mySqlDB_GetPublisherVASTTags(t *testing.T) { Queries: config.Queries{ GetPublisherVASTTagsQuery: "^SELECT (.+) FROM wrapper_publisher_partner_vast_tag (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ @@ -75,6 +76,7 @@ func Test_mySqlDB_GetPublisherVASTTags(t *testing.T) { Queries: config.Queries{ GetPublisherVASTTagsQuery: "^SELECT (.+) FROM wrapper_publisher_partner_vast_tag (.+)", }, + MaxDbContextTimeout: 1000, }, }, args: args{ diff --git a/modules/pubmatic/openwrap/entrypointhook.go b/modules/pubmatic/openwrap/entrypointhook.go index b6470994fb8..7e619b8f65f 100644 --- a/modules/pubmatic/openwrap/entrypointhook.go +++ b/modules/pubmatic/openwrap/entrypointhook.go @@ -133,8 +133,6 @@ func (m OpenWrap) handleEntrypointHook( rCtx.PubID = pubid } - rCtx.LoggerDisabled, rCtx.TrackerDisabled = m.pubFeatures.IsAnalyticsTrackingThrottled(rCtx.PubID, rCtx.ProfileID) - result.Reject = false return result, nil } diff --git a/modules/pubmatic/openwrap/entrypointhook_test.go b/modules/pubmatic/openwrap/entrypointhook_test.go index d1a588a7dc1..317c73c1681 100644 --- a/modules/pubmatic/openwrap/entrypointhook_test.go +++ b/modules/pubmatic/openwrap/entrypointhook_test.go @@ -13,7 +13,6 @@ import ( 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" - mock_publisherfeatures "github.com/prebid/prebid-server/v2/modules/pubmatic/openwrap/publisherfeature/mock" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) @@ -32,7 +31,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { in0 context.Context miCtx hookstage.ModuleInvocationContext payload hookstage.EntrypointPayload - setup func(*mock_metrics.MockMetricsEngine, *mock_publisherfeatures.MockFeature) + setup func(*mock_metrics.MockMetricsEngine) } tests := []struct { name string @@ -59,7 +58,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) {}, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -96,9 +95,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { - mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) - }, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -161,9 +158,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1,"wiid":"4df09505-d0b2-4d70-94d9-dc41e8e777f7"}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { - mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) - }, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -211,7 +206,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileids":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + setup: func(mme *mock_metrics.MockMetricsEngine) { mme.EXPECT().RecordBadRequests(gomock.Any(), 700) }, }, @@ -244,9 +239,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{"profileid":43563,"versionid":1}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { - mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) - }, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -305,9 +298,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{"profileid":43563,"versionid":1}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false,"debug":true}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { - mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) - }, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -366,7 +357,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { + setup: func(mme *mock_metrics.MockMetricsEngine) { mme.EXPECT().RecordBadRequests(gomock.Any(), 700) }, }, @@ -399,7 +390,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"imp":[{"tagid":"/43743431/DMDemo","ext":{"prebid":{"bidder":{"pubmatic":{"publisherId":"5890"}},"adunitcode":"div-gpt-ad-1460505748561-0"}},"id":"div-gpt-ad-1460505748561-0","banner":{"topframe":1,"format":[{"w":300,"h":250}]}}],"site":{"domain":"localhost:9999","publisher":{"domain":"localhost:9999","id":"5890"},"page":"http://localhost:9999/integrationExamples/gpt/owServer_example.html"},"device":{"w":1792,"h":446,"dnt":0,"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","language":"en","sua":{"source":1,"platform":{"brand":"macOS"},"browsers":[{"brand":"Google Chrome","version":["117"]},{"brand":"Not;A=Brand","version":["8"]},{"brand":"Chromium","version":["117"]}],"mobile":0}},"ext":{"prebid":{"auctiontimestamp":1697191822565,"targeting":{"includewinners":true,"includebidderkeys":true},"bidderparams":{"pubmatic":{"publisherId":"5890","wrapper":{}}},"channel":{"name":"pbjs","version":"v8.7.0-pre"},"createtids":false}},"id":"5bdd7da5-1166-40fe-a9cb-3bf3c3164cd3","test":0,"tmax":3000}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) {}, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -428,7 +419,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) {}, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -466,9 +457,7 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { }(), Body: []byte(`{"ext":{"wrapper":{"profileid":5890,"versionid":1}}}`), }, - setup: func(mme *mock_metrics.MockMetricsEngine, mpf *mock_publisherfeatures.MockFeature) { - mpf.EXPECT().IsAnalyticsTrackingThrottled(gomock.Any(), gomock.Any()) - }, + setup: func(mme *mock_metrics.MockMetricsEngine) {}, }, want: hookstage.HookResult[hookstage.EntrypointPayload]{ ModuleContext: hookstage.ModuleContext{ @@ -508,14 +497,11 @@ func TestOpenWrap_handleEntrypointHook(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockPubFeature := mock_publisherfeatures.NewMockFeature(ctrl) - - tt.args.setup(mockEngine, mockPubFeature) + tt.args.setup(mockEngine) m := OpenWrap{ cfg: tt.fields.cfg, cache: tt.fields.cache, metricEngine: mockEngine, - pubFeatures: mockPubFeature, } got, err := m.handleEntrypointHook(tt.args.in0, tt.args.miCtx, tt.args.payload) assert.Equal(t, err, tt.wantErr) diff --git a/modules/pubmatic/openwrap/models/constants.go b/modules/pubmatic/openwrap/models/constants.go index 82e44955498..376a4b46824 100755 --- a/modules/pubmatic/openwrap/models/constants.go +++ b/modules/pubmatic/openwrap/models/constants.go @@ -435,6 +435,11 @@ const ( ContextOWLoggerKey contextKey = "owlogger" ) +const ( + AnanlyticsThrottlingLoggerType = "wl" + AnanlyticsThrottlingTrackerType = "wt" +) + const ( Pipe = "|" BidIdSeparator = "::"