github.com/prebid/prebid-server/v2@v2.18.0/analytics/build/build_test.go (about)

     1  package build
     2  
     3  import (
     4  	"github.com/prebid/prebid-server/v2/openrtb_ext"
     5  	"github.com/prebid/prebid-server/v2/util/iputil"
     6  
     7  	"net/http"
     8  	"os"
     9  	"testing"
    10  
    11  	"github.com/prebid/openrtb/v20/openrtb2"
    12  	"github.com/prebid/prebid-server/v2/analytics"
    13  	"github.com/prebid/prebid-server/v2/config"
    14  	"github.com/prebid/prebid-server/v2/privacy"
    15  	"github.com/prebid/prebid-server/v2/util/ptrutil"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  const TEST_DIR string = "testFiles"
    20  
    21  func TestSampleModule(t *testing.T) {
    22  	var count int
    23  	am := initAnalytics(&count)
    24  	am.LogAuctionObject(&analytics.AuctionObject{
    25  		Status:         http.StatusOK,
    26  		RequestWrapper: &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()},
    27  		Errors:         nil,
    28  		Response:       &openrtb2.BidResponse{},
    29  	}, privacy.ActivityControl{})
    30  	if count != 1 {
    31  		t.Errorf("PBSAnalyticsModule failed at LogAuctionObject")
    32  	}
    33  
    34  	am.LogSetUIDObject(&analytics.SetUIDObject{
    35  		Status:  http.StatusOK,
    36  		Bidder:  "bidders string",
    37  		UID:     "uid",
    38  		Errors:  nil,
    39  		Success: true,
    40  	})
    41  	if count != 2 {
    42  		t.Errorf("PBSAnalyticsModule failed at LogSetUIDObject")
    43  	}
    44  
    45  	am.LogCookieSyncObject(&analytics.CookieSyncObject{})
    46  	if count != 3 {
    47  		t.Errorf("PBSAnalyticsModule failed at LogCookieSyncObject")
    48  	}
    49  
    50  	am.LogAmpObject(&analytics.AmpObject{RequestWrapper: &openrtb_ext.RequestWrapper{}}, privacy.ActivityControl{})
    51  	if count != 4 {
    52  		t.Errorf("PBSAnalyticsModule failed at LogAmpObject")
    53  	}
    54  
    55  	am.LogVideoObject(&analytics.VideoObject{RequestWrapper: &openrtb_ext.RequestWrapper{}}, privacy.ActivityControl{})
    56  	if count != 5 {
    57  		t.Errorf("PBSAnalyticsModule failed at LogVideoObject")
    58  	}
    59  
    60  	am.LogNotificationEventObject(&analytics.NotificationEvent{}, privacy.ActivityControl{})
    61  	if count != 6 {
    62  		t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject")
    63  	}
    64  }
    65  
    66  type sampleModule struct {
    67  	count *int
    68  }
    69  
    70  func (m *sampleModule) LogAuctionObject(ao *analytics.AuctionObject) { *m.count++ }
    71  
    72  func (m *sampleModule) LogVideoObject(vo *analytics.VideoObject) { *m.count++ }
    73  
    74  func (m *sampleModule) LogCookieSyncObject(cso *analytics.CookieSyncObject) { *m.count++ }
    75  
    76  func (m *sampleModule) LogSetUIDObject(so *analytics.SetUIDObject) { *m.count++ }
    77  
    78  func (m *sampleModule) LogAmpObject(ao *analytics.AmpObject) { *m.count++ }
    79  
    80  func (m *sampleModule) LogNotificationEventObject(ne *analytics.NotificationEvent) { *m.count++ }
    81  
    82  func initAnalytics(count *int) analytics.Runner {
    83  	modules := make(enabledAnalytics, 0)
    84  	modules["sampleModule"] = &sampleModule{count}
    85  	return &modules
    86  }
    87  
    88  func TestNewPBSAnalytics(t *testing.T) {
    89  	pbsAnalytics := New(&config.Analytics{})
    90  	instance := pbsAnalytics.(enabledAnalytics)
    91  
    92  	assert.Equal(t, len(instance), 0)
    93  }
    94  
    95  func TestNewPBSAnalytics_FileLogger(t *testing.T) {
    96  	if _, err := os.Stat(TEST_DIR); os.IsNotExist(err) {
    97  		if err = os.MkdirAll(TEST_DIR, 0755); err != nil {
    98  			t.Fatalf("Could not create test directory for FileLogger")
    99  		}
   100  	}
   101  	defer os.RemoveAll(TEST_DIR)
   102  	mod := New(&config.Analytics{File: config.FileLogs{Filename: TEST_DIR + "/test"}})
   103  	switch modType := mod.(type) {
   104  	case enabledAnalytics:
   105  		if len(enabledAnalytics(modType)) != 1 {
   106  			t.Fatalf("Failed to add analytics module")
   107  		}
   108  	default:
   109  		t.Fatalf("Failed to initialize analytics module")
   110  	}
   111  
   112  	pbsAnalytics := New(&config.Analytics{File: config.FileLogs{Filename: TEST_DIR + "/test"}})
   113  	instance := pbsAnalytics.(enabledAnalytics)
   114  
   115  	assert.Equal(t, len(instance), 1)
   116  }
   117  
   118  func TestNewPBSAnalytics_Pubstack(t *testing.T) {
   119  	pbsAnalyticsWithoutError := New(&config.Analytics{
   120  		Pubstack: config.Pubstack{
   121  			Enabled:   true,
   122  			ScopeId:   "scopeId",
   123  			IntakeUrl: "https://pubstack.io/intake",
   124  			Buffers: config.PubstackBuffer{
   125  				BufferSize: "100KB",
   126  				EventCount: 0,
   127  				Timeout:    "30s",
   128  			},
   129  			ConfRefresh: "2h",
   130  		},
   131  	})
   132  	instanceWithoutError := pbsAnalyticsWithoutError.(enabledAnalytics)
   133  
   134  	assert.Equal(t, len(instanceWithoutError), 1)
   135  
   136  	pbsAnalyticsWithError := New(&config.Analytics{
   137  		Pubstack: config.Pubstack{
   138  			Enabled: true,
   139  		},
   140  	})
   141  	instanceWithError := pbsAnalyticsWithError.(enabledAnalytics)
   142  	assert.Equal(t, len(instanceWithError), 0)
   143  }
   144  
   145  func TestNewModuleHttp(t *testing.T) {
   146  	agmaAnalyticsWithoutError := New(&config.Analytics{
   147  		Agma: config.AgmaAnalytics{
   148  			Enabled: true,
   149  			Endpoint: config.AgmaAnalyticsHttpEndpoint{
   150  				Url:     "http://localhost:8080",
   151  				Timeout: "1s",
   152  			},
   153  			Buffers: config.AgmaAnalyticsBuffer{
   154  				BufferSize: "100KB",
   155  				EventCount: 50,
   156  				Timeout:    "30s",
   157  			},
   158  			Accounts: []config.AgmaAnalyticsAccount{
   159  				{
   160  					PublisherId: "123",
   161  					Code:        "abc",
   162  				},
   163  			},
   164  		},
   165  	})
   166  	instanceWithoutError := agmaAnalyticsWithoutError.(enabledAnalytics)
   167  
   168  	assert.Equal(t, len(instanceWithoutError), 1)
   169  
   170  	agmaAnalyticsWithError := New(&config.Analytics{
   171  		Agma: config.AgmaAnalytics{
   172  			Enabled: true,
   173  		},
   174  	})
   175  	instanceWithError := agmaAnalyticsWithError.(enabledAnalytics)
   176  	assert.Equal(t, len(instanceWithError), 0)
   177  }
   178  
   179  func TestSampleModuleActivitiesAllowed(t *testing.T) {
   180  	var count int
   181  	am := initAnalytics(&count)
   182  
   183  	acAllowed := privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, true))
   184  
   185  	ao := &analytics.AuctionObject{
   186  		Status:         http.StatusOK,
   187  		RequestWrapper: &openrtb_ext.RequestWrapper{},
   188  		Errors:         nil,
   189  		Response:       &openrtb2.BidResponse{},
   190  	}
   191  
   192  	am.LogAuctionObject(ao, acAllowed)
   193  	if count != 1 {
   194  		t.Errorf("PBSAnalyticsModule failed at LogAuctionObject")
   195  	}
   196  
   197  	am.LogAmpObject(&analytics.AmpObject{RequestWrapper: &openrtb_ext.RequestWrapper{}}, acAllowed)
   198  	if count != 2 {
   199  		t.Errorf("PBSAnalyticsModule failed at LogAmpObject")
   200  	}
   201  
   202  	am.LogVideoObject(&analytics.VideoObject{RequestWrapper: &openrtb_ext.RequestWrapper{}}, acAllowed)
   203  	if count != 3 {
   204  		t.Errorf("PBSAnalyticsModule failed at LogVideoObject")
   205  	}
   206  
   207  	am.LogNotificationEventObject(&analytics.NotificationEvent{}, acAllowed)
   208  	if count != 4 {
   209  		t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject")
   210  	}
   211  }
   212  
   213  func TestSampleModuleActivitiesAllowedAndDenied(t *testing.T) {
   214  	var count int
   215  	am := initAnalytics(&count)
   216  
   217  	acAllowed := privacy.NewActivityControl(getActivityConfig("sampleModule", true, false, true))
   218  
   219  	rw := &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()}
   220  	ao := &analytics.AuctionObject{
   221  		RequestWrapper: rw,
   222  		Status:         http.StatusOK,
   223  		Errors:         nil,
   224  		Response:       &openrtb2.BidResponse{},
   225  	}
   226  
   227  	am.LogAuctionObject(ao, acAllowed)
   228  	if count != 1 {
   229  		t.Errorf("PBSAnalyticsModule failed at LogAuctionObject")
   230  	}
   231  
   232  	am.LogAmpObject(&analytics.AmpObject{RequestWrapper: rw}, acAllowed)
   233  	if count != 2 {
   234  		t.Errorf("PBSAnalyticsModule failed at LogAmpObject")
   235  	}
   236  
   237  	am.LogVideoObject(&analytics.VideoObject{RequestWrapper: rw}, acAllowed)
   238  	if count != 3 {
   239  		t.Errorf("PBSAnalyticsModule failed at LogVideoObject")
   240  	}
   241  
   242  	am.LogNotificationEventObject(&analytics.NotificationEvent{}, acAllowed)
   243  	if count != 4 {
   244  		t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject")
   245  	}
   246  }
   247  
   248  func TestSampleModuleActivitiesDenied(t *testing.T) {
   249  	var count int
   250  	am := initAnalytics(&count)
   251  
   252  	acDenied := privacy.NewActivityControl(getActivityConfig("sampleModule", false, true, true))
   253  
   254  	ao := &analytics.AuctionObject{
   255  		Status:   http.StatusOK,
   256  		Errors:   nil,
   257  		Response: &openrtb2.BidResponse{},
   258  	}
   259  
   260  	am.LogAuctionObject(ao, acDenied)
   261  	if count != 0 {
   262  		t.Errorf("PBSAnalyticsModule failed at LogAuctionObject")
   263  	}
   264  
   265  	am.LogAmpObject(&analytics.AmpObject{}, acDenied)
   266  	if count != 0 {
   267  		t.Errorf("PBSAnalyticsModule failed at LogAmpObject")
   268  	}
   269  
   270  	am.LogVideoObject(&analytics.VideoObject{}, acDenied)
   271  	if count != 0 {
   272  		t.Errorf("PBSAnalyticsModule failed at LogVideoObject")
   273  	}
   274  
   275  	am.LogNotificationEventObject(&analytics.NotificationEvent{}, acDenied)
   276  	if count != 0 {
   277  		t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject")
   278  	}
   279  }
   280  
   281  func TestEvaluateActivities(t *testing.T) {
   282  	testCases := []struct {
   283  		description             string
   284  		givenActivityControl    privacy.ActivityControl
   285  		expectedRequest         *openrtb_ext.RequestWrapper
   286  		expectedAllowActivities bool
   287  	}{
   288  		{
   289  			description:             "all blocked",
   290  			givenActivityControl:    privacy.NewActivityControl(getActivityConfig("sampleModule", false, false, false)),
   291  			expectedRequest:         nil,
   292  			expectedAllowActivities: false,
   293  		},
   294  		{
   295  			description:             "all allowed",
   296  			givenActivityControl:    privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, true)),
   297  			expectedRequest:         nil,
   298  			expectedAllowActivities: true,
   299  		},
   300  
   301  		{
   302  			description:          "ActivityTransmitUserFPD and ActivityTransmitPreciseGeo disabled",
   303  			givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, false, false)),
   304  			expectedRequest: &openrtb_ext.RequestWrapper{
   305  				BidRequest: &openrtb2.BidRequest{ID: "test_request", User: &openrtb2.User{ID: ""}, Device: &openrtb2.Device{IFA: "", IP: "127.0.0.0"}},
   306  			},
   307  			expectedAllowActivities: true,
   308  		},
   309  		{
   310  			description:          "ActivityTransmitUserFPD enabled, ActivityTransmitPreciseGeo disabled",
   311  			givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, false)),
   312  			expectedRequest: &openrtb_ext.RequestWrapper{
   313  				BidRequest: &openrtb2.BidRequest{ID: "test_request", User: &openrtb2.User{ID: "user-id"}, Device: &openrtb2.Device{IFA: "device-ifa", IP: "127.0.0.0"}},
   314  			},
   315  			expectedAllowActivities: true,
   316  		},
   317  	}
   318  
   319  	for _, test := range testCases {
   320  		t.Run(test.description, func(t *testing.T) {
   321  			rw := &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()}
   322  			resActivityAllowed, resRequest := evaluateActivities(rw, test.givenActivityControl, "sampleModule")
   323  			assert.Equal(t, test.expectedAllowActivities, resActivityAllowed)
   324  			if test.expectedRequest != nil {
   325  				assert.Equal(t, test.expectedRequest.User.ID, resRequest.User.ID)
   326  				assert.Equal(t, test.expectedRequest.Device.IFA, resRequest.Device.IFA)
   327  				assert.Equal(t, test.expectedRequest.Device.IP, resRequest.Device.IP)
   328  			} else {
   329  				assert.Nil(t, resRequest)
   330  			}
   331  
   332  		})
   333  	}
   334  
   335  }
   336  
   337  func getDefaultBidRequest() *openrtb2.BidRequest {
   338  	return &openrtb2.BidRequest{
   339  		ID:     "test_request",
   340  		User:   &openrtb2.User{ID: "user-id"},
   341  		Device: &openrtb2.Device{IFA: "device-ifa", IP: "127.0.0.1"},
   342  	}
   343  }
   344  
   345  func getActivityConfig(componentName string, allowReportAnalytics, allowTransmitUserFPD, allowTransmitPreciseGeo bool) *config.AccountPrivacy {
   346  	return &config.AccountPrivacy{
   347  		AllowActivities: &config.AllowActivities{
   348  			ReportAnalytics: config.Activity{
   349  				Default: ptrutil.ToPtr(true),
   350  				Rules: []config.ActivityRule{
   351  					{
   352  						Allow: allowReportAnalytics,
   353  						Condition: config.ActivityCondition{
   354  							ComponentName: []string{componentName},
   355  							ComponentType: []string{"analytics"},
   356  						},
   357  					},
   358  				},
   359  			},
   360  			TransmitUserFPD: config.Activity{
   361  				Default: ptrutil.ToPtr(true),
   362  				Rules: []config.ActivityRule{
   363  					{
   364  						Allow: allowTransmitUserFPD,
   365  						Condition: config.ActivityCondition{
   366  							ComponentName: []string{componentName},
   367  							ComponentType: []string{"analytics"},
   368  						},
   369  					},
   370  				},
   371  			},
   372  			TransmitPreciseGeo: config.Activity{
   373  				Default: ptrutil.ToPtr(true),
   374  				Rules: []config.ActivityRule{
   375  					{
   376  						Allow: allowTransmitPreciseGeo,
   377  						Condition: config.ActivityCondition{
   378  							ComponentName: []string{componentName},
   379  							ComponentType: []string{"analytics"},
   380  						},
   381  					},
   382  				},
   383  			},
   384  		},
   385  		IPv4Config: config.IPv4{
   386  			AnonKeepBits: iputil.IPv4DefaultMaskingBitSize,
   387  		},
   388  		IPv6Config: config.IPv6{
   389  			AnonKeepBits: iputil.IPv6DefaultMaskingBitSize,
   390  		},
   391  	}
   392  }
   393  
   394  type mockAnalytics struct {
   395  	lastLoggedAuctionBidRequest *openrtb2.BidRequest
   396  	lastLoggedAmpBidRequest     *openrtb2.BidRequest
   397  	lastLoggedVideoBidRequest   *openrtb2.BidRequest
   398  }
   399  
   400  func (m *mockAnalytics) LogAuctionObject(ao *analytics.AuctionObject) {
   401  	m.lastLoggedAuctionBidRequest = ao.RequestWrapper.BidRequest
   402  }
   403  
   404  func (m *mockAnalytics) LogAmpObject(ao *analytics.AmpObject) {
   405  	m.lastLoggedAmpBidRequest = ao.RequestWrapper.BidRequest
   406  }
   407  
   408  func (m *mockAnalytics) LogVideoObject(vo *analytics.VideoObject) {
   409  	m.lastLoggedVideoBidRequest = vo.RequestWrapper.BidRequest
   410  }
   411  
   412  func (m *mockAnalytics) LogCookieSyncObject(ao *analytics.CookieSyncObject) {}
   413  
   414  func (m *mockAnalytics) LogSetUIDObject(ao *analytics.SetUIDObject) {}
   415  
   416  func (m *mockAnalytics) LogNotificationEventObject(ao *analytics.NotificationEvent) {}
   417  
   418  func TestLogObject(t *testing.T) {
   419  	tests := []struct {
   420  		description           string
   421  		givenRequestWrapper   *openrtb_ext.RequestWrapper
   422  		givenEnabledAnalytics enabledAnalytics
   423  		givenActivityControl  bool
   424  		givenAuctionObject    *analytics.AuctionObject
   425  		givenAmpObject        *analytics.AmpObject
   426  		givenVideoObject      *analytics.VideoObject
   427  		expectedBidRequest1   *openrtb2.BidRequest
   428  		expectedBidRequest2   *openrtb2.BidRequest
   429  	}{
   430  		{
   431  			description:           "Multiple analytics modules, clone from evaluate activities, should expect both to have their information to be logged only -- auction",
   432  			givenEnabledAnalytics: enabledAnalytics{"adapter1": &mockAnalytics{}, "adapter2": &mockAnalytics{}},
   433  			givenActivityControl:  true,
   434  			givenAuctionObject: &analytics.AuctionObject{
   435  				Status:   http.StatusOK,
   436  				Errors:   nil,
   437  				Response: &openrtb2.BidResponse{},
   438  				RequestWrapper: &openrtb_ext.RequestWrapper{
   439  					BidRequest: &openrtb2.BidRequest{
   440  						ID:  "test_request",
   441  						Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   442  				},
   443  			},
   444  			expectedBidRequest1: &openrtb2.BidRequest{
   445  				ID:  "test_request",
   446  				Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true}}}}`)},
   447  			expectedBidRequest2: &openrtb2.BidRequest{
   448  				ID:  "test_request",
   449  				Ext: []byte(`{"prebid":{"analytics":{"adapter2":{"client-analytics":false}}}}`)},
   450  		},
   451  		{
   452  			description:           "Multiple analytics modules, no clone from evaluate activities, should expect both to have their information to be logged only -- amp",
   453  			givenEnabledAnalytics: enabledAnalytics{"adapter1": &mockAnalytics{}, "adapter2": &mockAnalytics{}},
   454  			givenActivityControl:  false,
   455  			givenAmpObject: &analytics.AmpObject{
   456  				Status:          http.StatusOK,
   457  				Errors:          nil,
   458  				AuctionResponse: &openrtb2.BidResponse{},
   459  				RequestWrapper: &openrtb_ext.RequestWrapper{
   460  					BidRequest: &openrtb2.BidRequest{
   461  						ID:  "test_request",
   462  						Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   463  				},
   464  			},
   465  			expectedBidRequest1: &openrtb2.BidRequest{
   466  				ID:  "test_request",
   467  				Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true}}}}`)},
   468  			expectedBidRequest2: &openrtb2.BidRequest{
   469  				ID:  "test_request",
   470  				Ext: []byte(`{"prebid":{"analytics":{"adapter2":{"client-analytics":false}}}}`)},
   471  		},
   472  		{
   473  			description:           "Single analytics module, clone from evaluate activities, should expect both to have their information to be logged only -- amp",
   474  			givenEnabledAnalytics: enabledAnalytics{"adapter1": &mockAnalytics{}},
   475  			givenActivityControl:  true,
   476  			givenAuctionObject: &analytics.AuctionObject{
   477  				Status:   http.StatusOK,
   478  				Errors:   nil,
   479  				Response: &openrtb2.BidResponse{},
   480  				RequestWrapper: &openrtb_ext.RequestWrapper{
   481  					BidRequest: &openrtb2.BidRequest{
   482  						ID:  "test_request",
   483  						Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   484  				},
   485  			},
   486  			expectedBidRequest1: &openrtb2.BidRequest{
   487  				ID:  "test_request",
   488  				Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true}}}}`)},
   489  		},
   490  		{
   491  			description:           "Single analytics module, adapter name not found, expect entire analytics object to be nil -- video",
   492  			givenEnabledAnalytics: enabledAnalytics{"unknownAdapter": &mockAnalytics{}},
   493  			givenActivityControl:  true,
   494  			givenVideoObject: &analytics.VideoObject{
   495  				Status:   http.StatusOK,
   496  				Errors:   nil,
   497  				Response: &openrtb2.BidResponse{},
   498  				RequestWrapper: &openrtb_ext.RequestWrapper{
   499  					BidRequest: &openrtb2.BidRequest{
   500  						ID:  "test_request",
   501  						Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   502  				},
   503  			},
   504  			expectedBidRequest1: &openrtb2.BidRequest{
   505  				ID:  "test_request",
   506  				Ext: nil,
   507  			},
   508  		},
   509  	}
   510  
   511  	for _, test := range tests {
   512  		t.Run(test.description, func(t *testing.T) {
   513  			ac := privacy.NewActivityControl(getActivityConfig("sampleModule", test.givenActivityControl, test.givenActivityControl, test.givenActivityControl))
   514  
   515  			var loggedBidReq1, loggedBidReq2 *openrtb2.BidRequest
   516  			switch {
   517  			case test.givenAuctionObject != nil:
   518  				test.givenEnabledAnalytics.LogAuctionObject(test.givenAuctionObject, ac)
   519  				loggedBidReq1 = test.givenEnabledAnalytics["adapter1"].(*mockAnalytics).lastLoggedAuctionBidRequest
   520  				if len(test.givenEnabledAnalytics) == 2 {
   521  					loggedBidReq2 = test.givenEnabledAnalytics["adapter2"].(*mockAnalytics).lastLoggedAuctionBidRequest
   522  				}
   523  			case test.givenAmpObject != nil:
   524  				test.givenEnabledAnalytics.LogAmpObject(test.givenAmpObject, ac)
   525  				loggedBidReq1 = test.givenEnabledAnalytics["adapter1"].(*mockAnalytics).lastLoggedAmpBidRequest
   526  				if len(test.givenEnabledAnalytics) == 2 {
   527  					loggedBidReq2 = test.givenEnabledAnalytics["adapter2"].(*mockAnalytics).lastLoggedAmpBidRequest
   528  				}
   529  			case test.givenVideoObject != nil:
   530  				test.givenEnabledAnalytics.LogVideoObject(test.givenVideoObject, ac)
   531  				loggedBidReq1 = test.givenEnabledAnalytics["unknownAdapter"].(*mockAnalytics).lastLoggedVideoBidRequest
   532  			}
   533  
   534  			assert.Equal(t, test.expectedBidRequest1, loggedBidReq1)
   535  			if test.expectedBidRequest2 != nil {
   536  				assert.Equal(t, test.expectedBidRequest2, loggedBidReq2)
   537  			}
   538  		})
   539  	}
   540  }
   541  
   542  func TestUpdateReqWrapperForAnalytics(t *testing.T) {
   543  	tests := []struct {
   544  		description               string
   545  		givenReqWrapper           *openrtb_ext.RequestWrapper
   546  		givenAdapterName          string
   547  		givenIsCloned             bool
   548  		expectedUpdatedBidRequest *openrtb2.BidRequest
   549  		expectedCloneRequest      *openrtb_ext.RequestWrapper
   550  	}{
   551  		{
   552  			description: "Adapter1 so Adapter2 info should be removed from ext.prebid.analytics",
   553  			givenReqWrapper: &openrtb_ext.RequestWrapper{
   554  				BidRequest: &openrtb2.BidRequest{
   555  					Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   556  			},
   557  			givenAdapterName: "adapter1",
   558  			givenIsCloned:    false,
   559  			expectedUpdatedBidRequest: &openrtb2.BidRequest{
   560  				Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true}}}}`),
   561  			},
   562  			expectedCloneRequest: &openrtb_ext.RequestWrapper{
   563  				BidRequest: &openrtb2.BidRequest{
   564  					Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   565  			},
   566  		},
   567  		{
   568  			description: "Adapter2 so Adapter1 info should be removed from ext.prebid.analytics",
   569  			givenReqWrapper: &openrtb_ext.RequestWrapper{
   570  				BidRequest: &openrtb2.BidRequest{
   571  					Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   572  			},
   573  			givenAdapterName: "adapter2",
   574  			givenIsCloned:    true,
   575  			expectedUpdatedBidRequest: &openrtb2.BidRequest{
   576  				Ext: []byte(`{"prebid":{"analytics":{"adapter2":{"client-analytics":false}}}}`),
   577  			},
   578  			expectedCloneRequest: nil,
   579  		},
   580  		{
   581  			description: "Given adapter not found in ext.prebid.analytics so remove entire object",
   582  			givenReqWrapper: &openrtb_ext.RequestWrapper{
   583  				BidRequest: &openrtb2.BidRequest{
   584  					Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   585  			},
   586  			givenAdapterName:          "adapterNotFound",
   587  			givenIsCloned:             false,
   588  			expectedUpdatedBidRequest: &openrtb2.BidRequest{},
   589  			expectedCloneRequest: &openrtb_ext.RequestWrapper{
   590  				BidRequest: &openrtb2.BidRequest{
   591  					Ext: []byte(`{"prebid":{"analytics":{"adapter1":{"client-analytics":true},"adapter2":{"client-analytics":false}}}}`)},
   592  			},
   593  		},
   594  		{
   595  			description:               "Given request is nil, check there are no exceptions",
   596  			givenReqWrapper:           nil,
   597  			givenAdapterName:          "adapter1",
   598  			givenIsCloned:             false,
   599  			expectedUpdatedBidRequest: nil,
   600  			expectedCloneRequest:      nil,
   601  		},
   602  	}
   603  
   604  	for _, test := range tests {
   605  		t.Run(test.description, func(t *testing.T) {
   606  			cloneReq := updateReqWrapperForAnalytics(test.givenReqWrapper, test.givenAdapterName, test.givenIsCloned)
   607  			if test.givenReqWrapper != nil {
   608  				assert.Equal(t, test.expectedUpdatedBidRequest, test.givenReqWrapper.BidRequest)
   609  			}
   610  			assert.Equal(t, test.expectedCloneRequest, cloneReq)
   611  		})
   612  	}
   613  }