github.com/prebid/prebid-server/v2@v2.18.0/bidadjustment/apply_test.go (about)

     1  package bidadjustment
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/prebid/openrtb/v20/openrtb2"
     7  	"github.com/prebid/prebid-server/v2/adapters"
     8  	"github.com/prebid/prebid-server/v2/openrtb_ext"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/mock"
    11  )
    12  
    13  func TestGetAndApply(t *testing.T) {
    14  	var (
    15  		adjCur string = "EUR"
    16  		bidCur string = "USA"
    17  	)
    18  
    19  	testCases := []struct {
    20  		name                   string
    21  		givenRuleToAdjustments map[string][]openrtb_ext.Adjustment
    22  		givenBidderName        openrtb_ext.BidderName
    23  		givenBidInfo           *adapters.TypedBid
    24  		givenBidType           string
    25  		setMock                func(m *mock.Mock)
    26  		expectedBidPrice       float64
    27  		expectedCurrency       string
    28  	}{
    29  		{
    30  			name: "CpmAdjustment",
    31  			givenBidInfo: &adapters.TypedBid{
    32  				Bid: &openrtb2.Bid{
    33  					Price:  10.0,
    34  					DealID: "dealId",
    35  				},
    36  			},
    37  			givenBidType: string(openrtb_ext.BidTypeBanner),
    38  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
    39  				"banner|bidderA|dealId": {
    40  					{
    41  						Type:     AdjustmentTypeCPM,
    42  						Value:    1.0,
    43  						Currency: adjCur,
    44  					},
    45  				},
    46  				"banner|bidderA|*": {
    47  					{
    48  						Type:  AdjustmentTypeMultiplier,
    49  						Value: 2.0,
    50  					},
    51  				},
    52  			},
    53  			givenBidderName:  "bidderA",
    54  			setMock:          func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) },
    55  			expectedBidPrice: 7.5,
    56  			expectedCurrency: bidCur,
    57  		},
    58  		{
    59  			name: "StaticAdjustment",
    60  			givenBidInfo: &adapters.TypedBid{
    61  				Bid: &openrtb2.Bid{
    62  					Price:  10.0,
    63  					DealID: "dealId",
    64  				},
    65  			},
    66  			givenBidType: string(openrtb_ext.BidTypeBanner),
    67  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
    68  				"*|bidderA|dealId": {
    69  					{
    70  						Type:     AdjustmentTypeCPM,
    71  						Value:    1.0,
    72  						Currency: adjCur,
    73  					},
    74  				},
    75  				"banner|bidderA|*": {
    76  					{
    77  						Type:     AdjustmentTypeStatic,
    78  						Value:    2.0,
    79  						Currency: adjCur,
    80  					},
    81  				},
    82  			},
    83  			givenBidderName:  "bidderA",
    84  			setMock:          nil,
    85  			expectedBidPrice: 2.0,
    86  			expectedCurrency: adjCur,
    87  		},
    88  		{
    89  			name: "MultiplierAdjustment",
    90  			givenBidInfo: &adapters.TypedBid{
    91  				Bid: &openrtb2.Bid{
    92  					Price:  10.0,
    93  					DealID: "dealId",
    94  				},
    95  			},
    96  			givenBidType: VideoInstream,
    97  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
    98  				"*|*|dealId": {
    99  					{
   100  						Type:     AdjustmentTypeCPM,
   101  						Value:    1.0,
   102  						Currency: adjCur,
   103  					},
   104  				},
   105  				"video-instream|*|*": {
   106  					{
   107  						Type:  AdjustmentTypeMultiplier,
   108  						Value: 2.0,
   109  					},
   110  				},
   111  			},
   112  			givenBidderName:  "bidderA",
   113  			setMock:          nil,
   114  			expectedBidPrice: 20.0,
   115  			expectedCurrency: bidCur,
   116  		},
   117  		{
   118  			name: "CpmAndMultiplierAdjustments",
   119  			givenBidInfo: &adapters.TypedBid{
   120  				Bid: &openrtb2.Bid{
   121  					Price:  10.0,
   122  					DealID: "dealId",
   123  				},
   124  			},
   125  			givenBidType: VideoInstream,
   126  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   127  				"video-instream|*|*": {
   128  					{
   129  						Type:  AdjustmentTypeMultiplier,
   130  						Value: 2.0,
   131  					},
   132  					{
   133  						Type:     AdjustmentTypeCPM,
   134  						Value:    1.0,
   135  						Currency: adjCur,
   136  					},
   137  				},
   138  			},
   139  			givenBidderName:  "bidderA",
   140  			setMock:          func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) },
   141  			expectedBidPrice: 17.5,
   142  			expectedCurrency: bidCur,
   143  		},
   144  		{
   145  			name: "DealIdPresentAndNegativeAdjustedPrice",
   146  			givenBidInfo: &adapters.TypedBid{
   147  				Bid: &openrtb2.Bid{
   148  					Price:  1.0,
   149  					DealID: "dealId",
   150  				},
   151  			},
   152  			givenBidType: VideoInstream,
   153  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   154  				"*|*|dealId": {
   155  					{
   156  						Type:     AdjustmentTypeCPM,
   157  						Value:    1.0,
   158  						Currency: adjCur,
   159  					},
   160  				},
   161  			},
   162  			givenBidderName:  "bidderA",
   163  			setMock:          func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) },
   164  			expectedBidPrice: 0.0,
   165  			expectedCurrency: bidCur,
   166  		},
   167  		{
   168  			name: "NoDealIdNegativeAdjustedPrice",
   169  			givenBidInfo: &adapters.TypedBid{
   170  				Bid: &openrtb2.Bid{
   171  					Price:  1.0,
   172  					DealID: "",
   173  				},
   174  			},
   175  			givenBidType: string(openrtb_ext.BidTypeAudio),
   176  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   177  				"*|*|*": {
   178  					{
   179  						Type:     AdjustmentTypeCPM,
   180  						Value:    1.0,
   181  						Currency: adjCur,
   182  					},
   183  				},
   184  			},
   185  			givenBidderName:  "bidderA",
   186  			setMock:          func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) },
   187  			expectedBidPrice: 0.1,
   188  			expectedCurrency: bidCur,
   189  		},
   190  		{
   191  			name: "NilMap",
   192  			givenBidInfo: &adapters.TypedBid{
   193  				Bid: &openrtb2.Bid{
   194  					Price:  10.0,
   195  					DealID: "dealId",
   196  				},
   197  			},
   198  			givenBidType:           string(openrtb_ext.BidTypeBanner),
   199  			givenRuleToAdjustments: nil,
   200  			givenBidderName:        "bidderA",
   201  			setMock:                nil,
   202  			expectedBidPrice:       10.0,
   203  			expectedCurrency:       bidCur,
   204  		},
   205  	}
   206  
   207  	for _, test := range testCases {
   208  		t.Run(test.name, func(t *testing.T) {
   209  			reqInfo := adapters.ExtraRequestInfo{}
   210  			if test.setMock != nil {
   211  				mockConversions := &mockConversions{}
   212  				test.setMock(&mockConversions.Mock)
   213  				reqInfo = adapters.NewExtraRequestInfo(mockConversions)
   214  			}
   215  			bidPrice, currencyAfterAdjustment := Apply(test.givenRuleToAdjustments, test.givenBidInfo, test.givenBidderName, bidCur, &reqInfo, test.givenBidType)
   216  			assert.Equal(t, test.expectedBidPrice, bidPrice)
   217  			assert.Equal(t, test.expectedCurrency, currencyAfterAdjustment)
   218  		})
   219  	}
   220  }
   221  
   222  type mockConversions struct {
   223  	mock.Mock
   224  }
   225  
   226  func (m *mockConversions) GetRate(from string, to string) (float64, error) {
   227  	args := m.Called(from, to)
   228  	return args.Get(0).(float64), args.Error(1)
   229  }
   230  
   231  func (m *mockConversions) GetRates() *map[string]map[string]float64 {
   232  	args := m.Called()
   233  	return args.Get(0).(*map[string]map[string]float64)
   234  }
   235  
   236  func TestApply(t *testing.T) {
   237  	var (
   238  		adjCur string = "EUR"
   239  		bidCur string = "USA"
   240  	)
   241  
   242  	testCases := []struct {
   243  		name             string
   244  		givenAdjustments []openrtb_ext.Adjustment
   245  		setMock          func(m *mock.Mock)
   246  		givenBidPrice    float64
   247  		expectedBidPrice float64
   248  		expectedCurrency string
   249  	}{
   250  		{
   251  			name:             "CpmAdjustment",
   252  			givenAdjustments: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 1.0, Currency: adjCur}},
   253  			givenBidPrice:    10.58687,
   254  			setMock:          func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) },
   255  			expectedBidPrice: 8.0869,
   256  			expectedCurrency: bidCur,
   257  		},
   258  		{
   259  			name:             "StaticAdjustment",
   260  			givenAdjustments: []openrtb_ext.Adjustment{{Type: AdjustmentTypeStatic, Value: 4.0, Currency: adjCur}},
   261  			givenBidPrice:    10.0,
   262  			setMock:          nil,
   263  			expectedBidPrice: 4.0,
   264  			expectedCurrency: adjCur,
   265  		},
   266  		{
   267  			name:             "MultiplierAdjustment",
   268  			givenAdjustments: []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 3.0}},
   269  			givenBidPrice:    10.0,
   270  			setMock:          nil,
   271  			expectedBidPrice: 30.0,
   272  			expectedCurrency: bidCur,
   273  		},
   274  		{
   275  			name:             "NilAdjustment",
   276  			givenAdjustments: nil,
   277  			givenBidPrice:    10.0,
   278  			setMock:          nil,
   279  			expectedBidPrice: 10.0,
   280  			expectedCurrency: bidCur,
   281  		},
   282  	}
   283  
   284  	for _, test := range testCases {
   285  		t.Run(test.name, func(t *testing.T) {
   286  			reqInfo := adapters.ExtraRequestInfo{}
   287  			if test.setMock != nil {
   288  				mockConversions := &mockConversions{}
   289  				test.setMock(&mockConversions.Mock)
   290  				reqInfo = adapters.NewExtraRequestInfo(mockConversions)
   291  			}
   292  
   293  			bidPrice, currencyAfterAdjustment := apply(test.givenAdjustments, test.givenBidPrice, bidCur, &reqInfo)
   294  			assert.Equal(t, test.expectedBidPrice, bidPrice)
   295  			assert.Equal(t, test.expectedCurrency, currencyAfterAdjustment)
   296  		})
   297  	}
   298  }
   299  
   300  func TestGet(t *testing.T) {
   301  	testCases := []struct {
   302  		name                   string
   303  		givenRuleToAdjustments map[string][]openrtb_ext.Adjustment
   304  		givenBidType           openrtb_ext.BidType
   305  		givenBidderName        openrtb_ext.BidderName
   306  		givenDealId            string
   307  		expected               []openrtb_ext.Adjustment
   308  	}{
   309  		{
   310  			name: "Priority1",
   311  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   312  				"banner|bidderA|dealId": {
   313  					{
   314  						Type:  AdjustmentTypeMultiplier,
   315  						Value: 1.1,
   316  					},
   317  				},
   318  				"banner|bidderA|*": {
   319  					{
   320  						Type:  AdjustmentTypeMultiplier,
   321  						Value: 2.0,
   322  					},
   323  				},
   324  			},
   325  			givenBidType:    openrtb_ext.BidTypeBanner,
   326  			givenBidderName: "bidderA",
   327  			givenDealId:     "dealId",
   328  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 1.1}},
   329  		},
   330  		{
   331  			name: "Priority2",
   332  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   333  				"banner|bidderA|*": {
   334  					{
   335  						Type:  AdjustmentTypeStatic,
   336  						Value: 5.0,
   337  					},
   338  				},
   339  				"banner|*|dealId": {
   340  					{
   341  						Type:  AdjustmentTypeMultiplier,
   342  						Value: 2.0,
   343  					},
   344  				},
   345  			},
   346  			givenBidType:    openrtb_ext.BidTypeBanner,
   347  			givenBidderName: "bidderA",
   348  			givenDealId:     "dealId",
   349  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeStatic, Value: 5.0}},
   350  		},
   351  		{
   352  			name: "Priority3",
   353  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   354  				"banner|*|dealId": {
   355  					{
   356  						Type:     AdjustmentTypeCPM,
   357  						Value:    3.0,
   358  						Currency: "USD",
   359  					},
   360  				},
   361  				"*|bidderA|dealId": {
   362  					{
   363  						Type:  AdjustmentTypeMultiplier,
   364  						Value: 1.1,
   365  					},
   366  				},
   367  			},
   368  			givenBidType:    openrtb_ext.BidTypeBanner,
   369  			givenBidderName: "bidderA",
   370  			givenDealId:     "dealId",
   371  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}},
   372  		},
   373  		{
   374  			name: "Priority4",
   375  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   376  				"*|bidderA|dealId": {
   377  					{
   378  						Type:     AdjustmentTypeCPM,
   379  						Value:    3.0,
   380  						Currency: "USD",
   381  					},
   382  				},
   383  				"banner|*|*": {
   384  					{
   385  						Type:  AdjustmentTypeMultiplier,
   386  						Value: 1.1,
   387  					},
   388  				},
   389  			},
   390  			givenBidType:    openrtb_ext.BidTypeBanner,
   391  			givenBidderName: "bidderA",
   392  			givenDealId:     "dealId",
   393  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}},
   394  		},
   395  		{
   396  			name: "Priority5",
   397  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   398  				"banner|*|*": {
   399  					{
   400  						Type:     AdjustmentTypeCPM,
   401  						Value:    3.0,
   402  						Currency: "USD",
   403  					},
   404  				},
   405  				"*|bidderA|*": {
   406  					{
   407  						Type:  AdjustmentTypeMultiplier,
   408  						Value: 1.1,
   409  					},
   410  				},
   411  			},
   412  			givenBidType:    openrtb_ext.BidTypeBanner,
   413  			givenBidderName: "bidderA",
   414  			givenDealId:     "dealId",
   415  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}},
   416  		},
   417  		{
   418  			name: "Priority6",
   419  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   420  				"*|bidderA|*": {
   421  					{
   422  						Type:     AdjustmentTypeCPM,
   423  						Value:    3.0,
   424  						Currency: "USD",
   425  					},
   426  				},
   427  				"*|*|dealId": {
   428  					{
   429  						Type:  AdjustmentTypeMultiplier,
   430  						Value: 1.1,
   431  					},
   432  				},
   433  			},
   434  			givenBidType:    openrtb_ext.BidTypeBanner,
   435  			givenBidderName: "bidderA",
   436  			givenDealId:     "dealId",
   437  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}},
   438  		},
   439  		{
   440  			name: "Priority7",
   441  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   442  				"*|*|dealId": {
   443  					{
   444  						Type:     AdjustmentTypeCPM,
   445  						Value:    3.0,
   446  						Currency: "USD",
   447  					},
   448  				},
   449  				"*|*|*": {
   450  					{
   451  						Type:  AdjustmentTypeMultiplier,
   452  						Value: 1.1,
   453  					},
   454  				},
   455  			},
   456  			givenBidType:    openrtb_ext.BidTypeBanner,
   457  			givenBidderName: "bidderA",
   458  			givenDealId:     "dealId",
   459  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}},
   460  		},
   461  		{
   462  			name: "Priority8",
   463  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   464  				"*|*|*": {
   465  					{
   466  						Type:  AdjustmentTypeMultiplier,
   467  						Value: 1.1,
   468  					},
   469  				},
   470  				"banner|bidderA|dealId": {
   471  					{
   472  						Type:  AdjustmentTypeMultiplier,
   473  						Value: 1.1,
   474  					},
   475  				},
   476  			},
   477  			givenBidType:    openrtb_ext.BidTypeBanner,
   478  			givenBidderName: "bidderB",
   479  			givenDealId:     "dealId",
   480  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 1.1}},
   481  		},
   482  		{
   483  			name: "NoDealID",
   484  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   485  				"banner|bidderA|*": {
   486  					{
   487  						Type:  AdjustmentTypeMultiplier,
   488  						Value: 1.1,
   489  					},
   490  				},
   491  				"banner|*|*": {
   492  					{
   493  						Type:  AdjustmentTypeMultiplier,
   494  						Value: 1.1,
   495  					},
   496  				},
   497  			},
   498  			givenBidType:    openrtb_ext.BidTypeBanner,
   499  			givenBidderName: "bidderA",
   500  			givenDealId:     "",
   501  			expected:        []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 1.1}},
   502  		},
   503  		{
   504  			name: "NoPriorityRulesMatch",
   505  			givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{
   506  				"banner|bidderA|dealId": {
   507  					{
   508  						Type:  AdjustmentTypeMultiplier,
   509  						Value: 1.1,
   510  					},
   511  				},
   512  				"banner|bidderA|*": {
   513  					{
   514  						Type:  AdjustmentTypeMultiplier,
   515  						Value: 2.0,
   516  					},
   517  				},
   518  			},
   519  			givenBidType:    openrtb_ext.BidTypeVideo,
   520  			givenBidderName: "bidderB",
   521  			givenDealId:     "diffDealId",
   522  			expected:        nil,
   523  		},
   524  	}
   525  
   526  	for _, test := range testCases {
   527  		t.Run(test.name, func(t *testing.T) {
   528  			adjArray := get(test.givenRuleToAdjustments, string(test.givenBidType), string(test.givenBidderName), test.givenDealId)
   529  			assert.Equal(t, test.expected, adjArray)
   530  		})
   531  	}
   532  }