github.com/prebid/prebid-server/v2@v2.18.0/floors/floors_test.go (about)

     1  package floors
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/prebid/openrtb/v20/openrtb2"
    10  	"github.com/prebid/prebid-server/v2/config"
    11  	"github.com/prebid/prebid-server/v2/currency"
    12  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    13  	"github.com/prebid/prebid-server/v2/util/jsonutil"
    14  	"github.com/prebid/prebid-server/v2/util/ptrutil"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestIsRequestEnabledWithFloor(t *testing.T) {
    19  	FalseFlag := false
    20  	TrueFlag := true
    21  
    22  	testCases := []struct {
    23  		name string
    24  		in   *openrtb_ext.ExtRequest
    25  		out  bool
    26  	}{
    27  		{
    28  			name: "Request With Nil Floors",
    29  			in:   &openrtb_ext.ExtRequest{},
    30  			out:  true,
    31  		},
    32  		{
    33  			name: "Request With Floors Disabled",
    34  			in:   &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Floors: &openrtb_ext.PriceFloorRules{Enabled: &FalseFlag}}},
    35  			out:  false,
    36  		},
    37  		{
    38  			name: "Request With Floors Enabled",
    39  			in:   &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Floors: &openrtb_ext.PriceFloorRules{Enabled: &TrueFlag}}},
    40  			out:  true,
    41  		},
    42  	}
    43  	for _, tc := range testCases {
    44  		t.Run(tc.name, func(t *testing.T) {
    45  			out := tc.in.Prebid.Floors.GetEnabled()
    46  			assert.Equal(t, out, tc.out, tc.name)
    47  		})
    48  	}
    49  }
    50  
    51  func getCurrencyRates(rates map[string]map[string]float64) currency.Conversions {
    52  	return currency.NewRates(rates)
    53  }
    54  
    55  type mockPriceFloorFetcher struct{}
    56  
    57  func (mpf *mockPriceFloorFetcher) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) {
    58  	return nil, openrtb_ext.FetchNone
    59  }
    60  
    61  func (mpf *mockPriceFloorFetcher) Stop() {}
    62  
    63  func TestEnrichWithPriceFloors(t *testing.T) {
    64  	rates := map[string]map[string]float64{
    65  		"USD": {
    66  			"INR": 70,
    67  			"EUR": 0.9,
    68  			"JPY": 5.09,
    69  		},
    70  	}
    71  
    72  	testAccountConfig := config.Account{
    73  		PriceFloors: config.AccountPriceFloors{
    74  			Enabled:        true,
    75  			UseDynamicData: false,
    76  			MaxRule:        100,
    77  			MaxSchemaDims:  5,
    78  		},
    79  	}
    80  
    81  	width := int64(300)
    82  	height := int64(600)
    83  
    84  	testCases := []struct {
    85  		name              string
    86  		bidRequestWrapper *openrtb_ext.RequestWrapper
    87  		account           config.Account
    88  		conversions       currency.Conversions
    89  		Skipped           bool
    90  		err               string
    91  		expFloorVal       float64
    92  		expFloorCur       string
    93  		expPriceFlrLoc    string
    94  		expSchemaVersion  int
    95  	}{
    96  		{
    97  			name: "Floors disabled in account config",
    98  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
    99  				BidRequest: &openrtb2.BidRequest{
   100  					Site: &openrtb2.Site{
   101  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   102  					},
   103  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   104  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   105  				},
   106  			},
   107  			account: config.Account{
   108  				PriceFloors: config.AccountPriceFloors{
   109  					Enabled: false,
   110  				},
   111  			},
   112  			err: "Floors feature is disabled at account or in the request",
   113  		},
   114  		{
   115  			name: "Floors disabled in req.ext.prebid.floors.Enabled=false config",
   116  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   117  				BidRequest: &openrtb2.BidRequest{
   118  					Site: &openrtb2.Site{
   119  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   120  					},
   121  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   122  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":false,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   123  				},
   124  			},
   125  			account: testAccountConfig,
   126  			err:     "Floors feature is disabled at account or in the request",
   127  		},
   128  		{
   129  			name: "Floors enabled in req.ext.prebid.floors.Enabled and enabled account config",
   130  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   131  				BidRequest: &openrtb2.BidRequest{
   132  					Site: &openrtb2.Site{
   133  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   134  					},
   135  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   136  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 2 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}},{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   137  				},
   138  			},
   139  			account:        testAccountConfig,
   140  			expFloorVal:    5,
   141  			expFloorCur:    "USD",
   142  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   143  		},
   144  		{
   145  			name: "Skiprate = 100, Floors enabled in  req.ext.prebid.floors.Enabled and account config: Floors singalling skipped ",
   146  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   147  				BidRequest: &openrtb2.BidRequest{
   148  					Site: &openrtb2.Site{
   149  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   150  					},
   151  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   152  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"skiprate": 100,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   153  				},
   154  			},
   155  			account: testAccountConfig,
   156  			Skipped: true,
   157  		},
   158  		{
   159  			name: "Single ModelGroup, Invalid Skiprate = 110: Floors singalling skipped",
   160  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   161  				BidRequest: &openrtb2.BidRequest{
   162  					Site: &openrtb2.Site{
   163  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   164  					},
   165  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   166  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"skiprate": 110,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   167  				},
   168  			},
   169  			account:        testAccountConfig,
   170  			err:            "Invalid SkipRate = '110' at ext.prebid.floors.skiprate",
   171  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   172  		},
   173  		{
   174  			name: "Multiple ModelGroups, Invalid Skiprate = 110: in one group, Floors singalling done using second ModelGroup",
   175  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   176  				BidRequest: &openrtb2.BidRequest{
   177  					Site: &openrtb2.Site{
   178  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   179  					},
   180  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   181  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":11,"floormincur":"USD","data":{"currency":"USD","floorsschemaversion":2,"modelgroups":[{"modelweight":50,"modelversion":"version2","schema":{"fields":["mediaType","size","domain"],"delimiter":"|"},"values":{"*|*|*":11.01,"*|*|www.website1.com":17.01},"default":21},{"modelweight":50,"modelversion":"version11","skiprate":110,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"},"values":{"*|300x250|*":11.01,"*|300x250|www.website1.com":100.01},"default":21}]},"enforcement":{"enforcepbs":true,"floordeals":true},"enabled":true}}}`),
   182  				},
   183  			},
   184  			account:          testAccountConfig,
   185  			err:              "Invalid Floor Model = 'version11' due to SkipRate = '110' is out of range (1-100)",
   186  			expFloorVal:      11.01,
   187  			expFloorCur:      "USD",
   188  			expPriceFlrLoc:   openrtb_ext.RequestLocation,
   189  			expSchemaVersion: 2,
   190  		},
   191  		{
   192  			name: "Rule selection with Site object, banner|300x600|www.website.com",
   193  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   194  				BidRequest: &openrtb2.BidRequest{
   195  					Site: &openrtb2.Site{
   196  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   197  					},
   198  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{W: &width, H: &height}}},
   199  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"BANNER|300x600|WWW.WEBSITE.COM":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   200  				},
   201  			},
   202  			account:        testAccountConfig,
   203  			expFloorVal:    5,
   204  			expFloorCur:    "USD",
   205  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   206  		},
   207  		{
   208  			name: "Rule selection with App object, *|*|www.test.com",
   209  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   210  				BidRequest: &openrtb2.BidRequest{
   211  					App: &openrtb2.App{
   212  						Domain: "www.test.com",
   213  					},
   214  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{W: &width, H: &height}}},
   215  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website.com":5,"*|*|www.test.com":15,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   216  				},
   217  			},
   218  			account:        testAccountConfig,
   219  			expFloorVal:    15,
   220  			expFloorCur:    "USD",
   221  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   222  		},
   223  		{
   224  			name: "Floors Signalling not done as req.ext.prebid.floors not provided",
   225  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   226  				BidRequest: &openrtb2.BidRequest{
   227  					App: &openrtb2.App{
   228  						Domain: "www.test.com",
   229  					},
   230  					Imp: []openrtb2.Imp{{ID: "1234", BidFloor: 10, BidFloorCur: "EUR", Banner: &openrtb2.Banner{W: &width, H: &height}}},
   231  					Ext: json.RawMessage(`{"prebid":{}}`),
   232  				},
   233  			},
   234  			account:        testAccountConfig,
   235  			expFloorVal:    10,
   236  			expFloorCur:    "EUR",
   237  			expPriceFlrLoc: openrtb_ext.NoDataLocation,
   238  			err:            "Empty Floors data",
   239  		},
   240  		{
   241  			name: "BidFloor(USD) Less than MinBidFloor(INR) with different currency",
   242  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   243  				BidRequest: &openrtb2.BidRequest{
   244  					Site: &openrtb2.Site{
   245  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   246  					},
   247  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   248  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":80,"floormincur":"INR","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":1,"*|*|www.test.com":15,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   249  				},
   250  			},
   251  			account:        testAccountConfig,
   252  			expFloorVal:    1.1429,
   253  			expFloorCur:    "USD",
   254  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   255  		},
   256  		{
   257  			name: "BidFloor(INR) Less than MinBidFloor(USD) with different currency",
   258  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   259  				BidRequest: &openrtb2.BidRequest{
   260  					Site: &openrtb2.Site{
   261  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   262  					},
   263  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   264  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":1,"floormincur":"USD","data":{"currency":"INR","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com":60,"*|*|www.test.com":65,"*|*|*":67},"Default":50,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   265  				},
   266  			},
   267  			account:        testAccountConfig,
   268  			expFloorVal:    70,
   269  			expFloorCur:    "INR",
   270  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   271  		},
   272  		{
   273  			name: "BidFloor is greater than MinBidFloor with same currency",
   274  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   275  				BidRequest: &openrtb2.BidRequest{
   276  					Site: &openrtb2.Site{
   277  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   278  					},
   279  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   280  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":1,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com":2,"*|*|www.test.com":1.5,"*|*|*":1.7},"Default":5,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   281  				},
   282  			},
   283  			account:        testAccountConfig,
   284  			expFloorVal:    2,
   285  			expFloorCur:    "USD",
   286  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   287  		},
   288  		{
   289  			name: "BidFloor Less than MinBidFloor with same currency",
   290  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   291  				BidRequest: &openrtb2.BidRequest{
   292  					Site: &openrtb2.Site{
   293  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   294  					},
   295  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   296  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":3,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com":2,"*|*|www.test.com":1.5,"*|*|*":1.7},"Default":5,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   297  				},
   298  			},
   299  			account:        testAccountConfig,
   300  			expFloorVal:    3,
   301  			expFloorCur:    "USD",
   302  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   303  		},
   304  		{
   305  			name: "No Rule matching, default value provided",
   306  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   307  				BidRequest: &openrtb2.BidRequest{
   308  					Site: &openrtb2.Site{
   309  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   310  					},
   311  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   312  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com1":2,"*|*|www.test2.com":1.5},"schema":{"fields":["mediaType","size","domain"]}, "default": 20}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   313  				},
   314  			},
   315  			account:        testAccountConfig,
   316  			expFloorVal:    20,
   317  			expFloorCur:    "USD",
   318  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   319  		},
   320  		{
   321  			name: "No Rule matching, default value less than floorMin",
   322  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   323  				BidRequest: &openrtb2.BidRequest{
   324  					Site: &openrtb2.Site{
   325  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   326  					},
   327  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   328  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":15,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com1":2,"*|*|www.test2.com":1.5},"schema":{"fields":["mediaType","size","domain"]}, "default": 5}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   329  				},
   330  			},
   331  			account:        testAccountConfig,
   332  			expFloorVal:    15,
   333  			expFloorCur:    "USD",
   334  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   335  		},
   336  		{
   337  			name: "imp.bidfloor provided, No Rule matching, MinBidFloor provided",
   338  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   339  				BidRequest: &openrtb2.BidRequest{
   340  					Site: &openrtb2.Site{
   341  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   342  					},
   343  					Imp: []openrtb2.Imp{{ID: "1234", BidFloor: 100, BidFloorCur: "INR", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   344  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":2,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com1":2,"*|*|www.test2.com":1.5},"schema":{"fields":["mediaType","size","domain"]}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   345  				},
   346  			},
   347  			account:        testAccountConfig,
   348  			expFloorVal:    100,
   349  			expFloorCur:    "INR",
   350  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   351  		},
   352  		{
   353  			name:              "Empty RequestWrapper ",
   354  			bidRequestWrapper: nil,
   355  			account:           testAccountConfig,
   356  			err:               "Empty bidrequest",
   357  		},
   358  		{
   359  			name: "Invalid Floor Min Currency",
   360  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   361  				BidRequest: &openrtb2.BidRequest{
   362  					Site: &openrtb2.Site{
   363  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   364  					},
   365  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   366  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":80,"floormincur":"ABCD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":1,"*|*|www.test.com":15,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   367  				},
   368  			},
   369  			account:        testAccountConfig,
   370  			err:            "Error in getting FloorMin value : 'currency: tag is not well-formed'",
   371  			expPriceFlrLoc: openrtb_ext.RequestLocation,
   372  		},
   373  	}
   374  
   375  	for _, tc := range testCases {
   376  		t.Run(tc.name, func(t *testing.T) {
   377  
   378  			ErrList := EnrichWithPriceFloors(tc.bidRequestWrapper, tc.account, getCurrencyRates(rates), &mockPriceFloorFetcher{})
   379  			if tc.bidRequestWrapper != nil {
   380  				assert.Equal(t, tc.bidRequestWrapper.Imp[0].BidFloor, tc.expFloorVal, tc.name)
   381  				assert.Equal(t, tc.bidRequestWrapper.Imp[0].BidFloorCur, tc.expFloorCur, tc.name)
   382  				requestExt, err := tc.bidRequestWrapper.GetRequestExt()
   383  				if err == nil {
   384  					if tc.Skipped {
   385  						assert.Equal(t, *requestExt.GetPrebid().Floors.Skipped, tc.Skipped, tc.name)
   386  					} else {
   387  						assert.Equal(t, requestExt.GetPrebid().Floors.PriceFloorLocation, tc.expPriceFlrLoc, tc.name)
   388  						if tc.expSchemaVersion != 0 {
   389  							assert.Equal(t, requestExt.GetPrebid().Floors.Data.FloorsSchemaVersion, tc.expSchemaVersion, tc.name)
   390  						}
   391  					}
   392  				}
   393  			}
   394  			if len(ErrList) > 0 {
   395  				assert.Equal(t, ErrList[0].Error(), tc.err, tc.name)
   396  			}
   397  		})
   398  	}
   399  }
   400  
   401  func getTrue() *bool {
   402  	trueFlag := true
   403  	return &trueFlag
   404  }
   405  
   406  func getFalse() *bool {
   407  	falseFlag := false
   408  	return &falseFlag
   409  }
   410  
   411  type MockFetch struct {
   412  	FakeFetch func(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string)
   413  }
   414  
   415  func (m *MockFetch) Stop() {}
   416  
   417  func (m *MockFetch) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) {
   418  
   419  	if !configs.UseDynamicData {
   420  		return nil, openrtb_ext.FetchNone
   421  	}
   422  	priceFloors := openrtb_ext.PriceFloorRules{
   423  		Enabled:            getTrue(),
   424  		PriceFloorLocation: openrtb_ext.RequestLocation,
   425  		Enforcement: &openrtb_ext.PriceFloorEnforcement{
   426  			EnforcePBS:  getTrue(),
   427  			EnforceRate: 100,
   428  			FloorDeals:  getTrue(),
   429  		},
   430  		Data: &openrtb_ext.PriceFloorData{
   431  			Currency: "USD",
   432  			ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   433  				{
   434  					ModelVersion: "Version 101",
   435  					Currency:     "USD",
   436  					Values: map[string]float64{
   437  						"banner|300x600|www.website5.com": 15,
   438  						"*|*|*":                           25,
   439  					},
   440  					Schema: openrtb_ext.PriceFloorSchema{
   441  						Fields:    []string{"mediaType", "size", "domain"},
   442  						Delimiter: "|",
   443  					},
   444  				},
   445  			},
   446  		},
   447  	}
   448  	return &priceFloors, openrtb_ext.FetchSuccess
   449  }
   450  
   451  func TestResolveFloors(t *testing.T) {
   452  	rates := map[string]map[string]float64{
   453  		"USD": {
   454  			"INR": 70,
   455  			"EUR": 0.9,
   456  			"JPY": 5.09,
   457  		},
   458  	}
   459  
   460  	testCases := []struct {
   461  		name              string
   462  		bidRequestWrapper *openrtb_ext.RequestWrapper
   463  		account           config.Account
   464  		conversions       currency.Conversions
   465  		fetcher           FloorFetcher
   466  		expErr            []error
   467  		expFloors         *openrtb_ext.PriceFloorRules
   468  	}{
   469  		{
   470  			name: "Dynamic fetch disabled, floors from request selected",
   471  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   472  				BidRequest: &openrtb2.BidRequest{
   473  					Site: &openrtb2.Site{
   474  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   475  					},
   476  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   477  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   478  				},
   479  			},
   480  			account: config.Account{
   481  				PriceFloors: config.AccountPriceFloors{
   482  					Enabled:        true,
   483  					UseDynamicData: false,
   484  				},
   485  			},
   486  			fetcher: &MockFetch{},
   487  			expFloors: &openrtb_ext.PriceFloorRules{
   488  				Enabled:            getTrue(),
   489  				FetchStatus:        openrtb_ext.FetchNone,
   490  				PriceFloorLocation: openrtb_ext.RequestLocation,
   491  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   492  					EnforcePBS:  getTrue(),
   493  					EnforceRate: 100,
   494  					FloorDeals:  getTrue(),
   495  				},
   496  				Data: &openrtb_ext.PriceFloorData{
   497  					Currency: "USD",
   498  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   499  						{
   500  							ModelVersion: "model 1 from req",
   501  							Currency:     "USD",
   502  							Values: map[string]float64{
   503  								"banner|300x600|www.website5.com": 5,
   504  								"*|*|*":                           7,
   505  							},
   506  							Schema: openrtb_ext.PriceFloorSchema{
   507  								Fields:    []string{"mediaType", "size", "domain"},
   508  								Delimiter: "|",
   509  							},
   510  						},
   511  					},
   512  				},
   513  			},
   514  		},
   515  		{
   516  			name: "Dynamic fetch enabled, floors from fetched selected",
   517  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   518  				BidRequest: &openrtb2.BidRequest{
   519  					Site: &openrtb2.Site{
   520  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   521  					},
   522  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   523  				},
   524  			},
   525  			account: config.Account{
   526  				PriceFloors: config.AccountPriceFloors{
   527  					Enabled:        true,
   528  					UseDynamicData: true,
   529  				},
   530  			},
   531  			fetcher: &MockFetch{},
   532  			expFloors: &openrtb_ext.PriceFloorRules{
   533  				Enabled:            getTrue(),
   534  				FetchStatus:        openrtb_ext.FetchSuccess,
   535  				PriceFloorLocation: openrtb_ext.FetchLocation,
   536  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   537  					EnforcePBS:  getTrue(),
   538  					FloorDeals:  getTrue(),
   539  					EnforceRate: 100,
   540  				},
   541  				Data: &openrtb_ext.PriceFloorData{
   542  					Currency: "USD",
   543  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   544  						{
   545  							ModelVersion: "Version 101",
   546  							Currency:     "USD",
   547  							Values: map[string]float64{
   548  								"banner|300x600|www.website5.com": 15,
   549  								"*|*|*":                           25,
   550  							},
   551  							Schema: openrtb_ext.PriceFloorSchema{
   552  								Fields:    []string{"mediaType", "size", "domain"},
   553  								Delimiter: "|",
   554  							},
   555  						},
   556  					},
   557  				},
   558  			},
   559  		},
   560  		{
   561  			name: "Dynamic fetch enabled, floors formed after merging",
   562  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   563  				BidRequest: &openrtb2.BidRequest{
   564  					Site: &openrtb2.Site{
   565  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   566  					},
   567  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   568  					Ext: json.RawMessage(`{"prebid":{"floors":{"floormincur":"EUR","enabled":true,"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"floormin":10.11,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   569  				},
   570  			},
   571  			account: config.Account{
   572  				PriceFloors: config.AccountPriceFloors{
   573  					Enabled:        true,
   574  					UseDynamicData: true,
   575  				},
   576  			},
   577  			fetcher: &MockFetch{},
   578  			expFloors: &openrtb_ext.PriceFloorRules{
   579  				Enabled:            getTrue(),
   580  				FloorMin:           10.11,
   581  				FloorMinCur:        "EUR",
   582  				FetchStatus:        openrtb_ext.FetchSuccess,
   583  				PriceFloorLocation: openrtb_ext.FetchLocation,
   584  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   585  					EnforcePBS:  getTrue(),
   586  					EnforceRate: 100,
   587  					FloorDeals:  getTrue(),
   588  				},
   589  				Data: &openrtb_ext.PriceFloorData{
   590  					Currency: "USD",
   591  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   592  						{
   593  							ModelVersion: "Version 101",
   594  							Currency:     "USD",
   595  							Values: map[string]float64{
   596  								"banner|300x600|www.website5.com": 15,
   597  								"*|*|*":                           25,
   598  							},
   599  							Schema: openrtb_ext.PriceFloorSchema{
   600  								Fields:    []string{"mediaType", "size", "domain"},
   601  								Delimiter: "|",
   602  							},
   603  						},
   604  					},
   605  				},
   606  			},
   607  		},
   608  		{
   609  			name: "Dynamic fetch disabled, only enforcement object present in req.ext",
   610  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   611  				BidRequest: &openrtb2.BidRequest{
   612  					Site: &openrtb2.Site{
   613  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   614  					},
   615  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   616  					Ext: json.RawMessage(`{"prebid":{"floors":{"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   617  				},
   618  			},
   619  			account: config.Account{
   620  				PriceFloors: config.AccountPriceFloors{
   621  					Enabled:        true,
   622  					UseDynamicData: false,
   623  				},
   624  			},
   625  			fetcher: &MockFetch{},
   626  			expFloors: &openrtb_ext.PriceFloorRules{
   627  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   628  					EnforcePBS:  getTrue(),
   629  					EnforceRate: 100,
   630  					FloorDeals:  getTrue(),
   631  				},
   632  				FetchStatus:        openrtb_ext.FetchNone,
   633  				PriceFloorLocation: openrtb_ext.RequestLocation,
   634  			},
   635  		},
   636  		{
   637  			name: "Dynamic fetch enabled, floors from fetched selected and new URL is updated",
   638  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   639  				BidRequest: &openrtb2.BidRequest{
   640  					Site: &openrtb2.Site{
   641  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   642  					},
   643  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   644  					Ext: json.RawMessage(`{"prebid":{"floors":{"floorendpoint":{"url":"http://test.com/floor"},"enabled":true}}}`),
   645  				},
   646  			},
   647  			account: config.Account{
   648  				PriceFloors: config.AccountPriceFloors{
   649  					Enabled:        true,
   650  					UseDynamicData: true,
   651  				},
   652  			},
   653  			fetcher: &MockFetch{},
   654  			expFloors: &openrtb_ext.PriceFloorRules{
   655  				Enabled:            getTrue(),
   656  				FetchStatus:        openrtb_ext.FetchSuccess,
   657  				PriceFloorLocation: openrtb_ext.FetchLocation,
   658  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   659  					EnforcePBS:  getTrue(),
   660  					FloorDeals:  getTrue(),
   661  					EnforceRate: 100,
   662  				},
   663  				Location: &openrtb_ext.PriceFloorEndpoint{
   664  					URL: "http://test.com/floor",
   665  				},
   666  				Data: &openrtb_ext.PriceFloorData{
   667  					Currency: "USD",
   668  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   669  						{
   670  							ModelVersion: "Version 101",
   671  							Currency:     "USD",
   672  							Values: map[string]float64{
   673  								"banner|300x600|www.website5.com": 15,
   674  								"*|*|*":                           25,
   675  							},
   676  							Schema: openrtb_ext.PriceFloorSchema{
   677  								Fields:    []string{"mediaType", "size", "domain"},
   678  								Delimiter: "|",
   679  							},
   680  						},
   681  					},
   682  				},
   683  			},
   684  		},
   685  		{
   686  			name: "Dynamic Fetch Enabled but price floor fetcher is nil, floors from request is selected",
   687  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   688  				BidRequest: &openrtb2.BidRequest{
   689  					Site: &openrtb2.Site{
   690  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   691  					},
   692  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   693  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   694  				},
   695  			},
   696  			account: config.Account{
   697  				PriceFloors: config.AccountPriceFloors{
   698  					Enabled:        true,
   699  					UseDynamicData: true,
   700  				},
   701  			},
   702  			fetcher: nil,
   703  			expFloors: &openrtb_ext.PriceFloorRules{
   704  				Enabled:            getTrue(),
   705  				FetchStatus:        openrtb_ext.FetchNone,
   706  				PriceFloorLocation: openrtb_ext.RequestLocation,
   707  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   708  					EnforcePBS:  getTrue(),
   709  					EnforceRate: 100,
   710  					FloorDeals:  getTrue(),
   711  				},
   712  				Data: &openrtb_ext.PriceFloorData{
   713  					Currency: "USD",
   714  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   715  						{
   716  							ModelVersion: "model 1 from req",
   717  							Currency:     "USD",
   718  							Values: map[string]float64{
   719  								"banner|300x600|www.website5.com": 5,
   720  								"*|*|*":                           7,
   721  							},
   722  							Schema: openrtb_ext.PriceFloorSchema{
   723  								Fields:    []string{"mediaType", "size", "domain"},
   724  								Delimiter: "|",
   725  							},
   726  						},
   727  					},
   728  				},
   729  			},
   730  		},
   731  		{
   732  			name: "Dynamic Fetch Enabled but price floor fetcher is nil and request has no floors",
   733  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   734  				BidRequest: &openrtb2.BidRequest{
   735  					Site: &openrtb2.Site{
   736  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   737  					},
   738  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   739  					Ext: json.RawMessage(`{"prebid":{}}`),
   740  				},
   741  			},
   742  			account: config.Account{
   743  				PriceFloors: config.AccountPriceFloors{
   744  					Enabled:        true,
   745  					UseDynamicData: true,
   746  				},
   747  			},
   748  			fetcher: nil,
   749  			expFloors: &openrtb_ext.PriceFloorRules{
   750  				FetchStatus:        openrtb_ext.FetchNone,
   751  				PriceFloorLocation: openrtb_ext.NoDataLocation,
   752  			},
   753  		},
   754  	}
   755  
   756  	for _, tc := range testCases {
   757  		t.Run(tc.name, func(t *testing.T) {
   758  			resolvedFloors, _ := resolveFloors(tc.account, tc.bidRequestWrapper, getCurrencyRates(rates), tc.fetcher)
   759  			assert.Equal(t, resolvedFloors, tc.expFloors, tc.name)
   760  		})
   761  	}
   762  }
   763  
   764  type MockFetchDataRate0 struct{}
   765  
   766  func (m *MockFetchDataRate0) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) {
   767  
   768  	if !configs.UseDynamicData {
   769  		return nil, openrtb_ext.FetchNone
   770  	}
   771  	priceFloors := openrtb_ext.PriceFloorRules{
   772  		Enabled:            getTrue(),
   773  		PriceFloorLocation: openrtb_ext.RequestLocation,
   774  		Enforcement: &openrtb_ext.PriceFloorEnforcement{
   775  			EnforcePBS:  getTrue(),
   776  			EnforceRate: 100,
   777  			FloorDeals:  getTrue(),
   778  		},
   779  		Data: &openrtb_ext.PriceFloorData{
   780  			Currency: "USD",
   781  			ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   782  				{
   783  					ModelVersion: "model from fetched",
   784  					Currency:     "USD",
   785  					Values: map[string]float64{
   786  						"banner|300x600|www.website5.com": 15,
   787  						"*|*|*":                           25,
   788  					},
   789  					Schema: openrtb_ext.PriceFloorSchema{
   790  						Fields: []string{"mediaType", "size", "domain"},
   791  					},
   792  				},
   793  			},
   794  			FetchRate: ptrutil.ToPtr(0),
   795  		},
   796  	}
   797  	return &priceFloors, openrtb_ext.FetchSuccess
   798  }
   799  
   800  func (m *MockFetchDataRate0) Stop() {
   801  
   802  }
   803  
   804  type MockFetchDataRate100 struct{}
   805  
   806  func (m *MockFetchDataRate100) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) {
   807  
   808  	if !configs.UseDynamicData {
   809  		return nil, openrtb_ext.FetchNone
   810  	}
   811  	priceFloors := openrtb_ext.PriceFloorRules{
   812  		Enabled:            getTrue(),
   813  		PriceFloorLocation: openrtb_ext.RequestLocation,
   814  		Enforcement: &openrtb_ext.PriceFloorEnforcement{
   815  			EnforcePBS:  getTrue(),
   816  			EnforceRate: 100,
   817  			FloorDeals:  getTrue(),
   818  		},
   819  		Data: &openrtb_ext.PriceFloorData{
   820  			Currency: "USD",
   821  			ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   822  				{
   823  					ModelVersion: "model from fetched",
   824  					Currency:     "USD",
   825  					Values: map[string]float64{
   826  						"banner|300x600|www.website5.com": 15,
   827  						"*|*|*":                           25,
   828  					},
   829  					Schema: openrtb_ext.PriceFloorSchema{
   830  						Fields: []string{"mediaType", "size", "domain"},
   831  					},
   832  				},
   833  			},
   834  			FetchRate: ptrutil.ToPtr(100),
   835  		},
   836  	}
   837  	return &priceFloors, openrtb_ext.FetchSuccess
   838  }
   839  
   840  func (m *MockFetchDataRate100) Stop() {
   841  
   842  }
   843  
   844  type MockFetchDataRateNotProvided struct{}
   845  
   846  func (m *MockFetchDataRateNotProvided) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) {
   847  
   848  	if !configs.UseDynamicData {
   849  		return nil, openrtb_ext.FetchNone
   850  	}
   851  	priceFloors := openrtb_ext.PriceFloorRules{
   852  		Enabled:            getTrue(),
   853  		PriceFloorLocation: openrtb_ext.RequestLocation,
   854  		Enforcement: &openrtb_ext.PriceFloorEnforcement{
   855  			EnforcePBS:  getTrue(),
   856  			EnforceRate: 100,
   857  			FloorDeals:  getTrue(),
   858  		},
   859  		Data: &openrtb_ext.PriceFloorData{
   860  			Currency: "USD",
   861  			ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   862  				{
   863  					ModelVersion: "model from fetched",
   864  					Currency:     "USD",
   865  					Values: map[string]float64{
   866  						"banner|300x600|www.website5.com": 5,
   867  						"*|*|*":                           15,
   868  					},
   869  					Schema: openrtb_ext.PriceFloorSchema{
   870  						Fields: []string{"mediaType", "size", "domain"},
   871  					},
   872  				},
   873  			},
   874  		},
   875  	}
   876  	return &priceFloors, openrtb_ext.FetchSuccess
   877  }
   878  
   879  func (m *MockFetchDataRateNotProvided) Stop() {
   880  
   881  }
   882  
   883  func TestResolveFloorsWithUseDataRate(t *testing.T) {
   884  	rates := map[string]map[string]float64{}
   885  
   886  	testCases := []struct {
   887  		name              string
   888  		bidRequestWrapper *openrtb_ext.RequestWrapper
   889  		account           config.Account
   890  		conversions       currency.Conversions
   891  		expErr            []error
   892  		expFloors         *openrtb_ext.PriceFloorRules
   893  		fetcher           FloorFetcher
   894  	}{
   895  		{
   896  			name:    "Dynamic fetch enabled, floors from request selected as data rate 0",
   897  			fetcher: &MockFetchDataRate0{},
   898  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   899  				BidRequest: &openrtb2.BidRequest{
   900  					Site: &openrtb2.Site{
   901  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   902  					},
   903  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   904  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   905  				},
   906  			},
   907  			account: config.Account{
   908  				PriceFloors: config.AccountPriceFloors{
   909  					Enabled:        true,
   910  					UseDynamicData: true,
   911  				},
   912  			},
   913  			expFloors: &openrtb_ext.PriceFloorRules{
   914  				Enabled:            getTrue(),
   915  				FetchStatus:        openrtb_ext.FetchNone,
   916  				PriceFloorLocation: openrtb_ext.RequestLocation,
   917  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   918  					EnforcePBS:  getTrue(),
   919  					FloorDeals:  getTrue(),
   920  					EnforceRate: 100,
   921  				},
   922  				Data: &openrtb_ext.PriceFloorData{
   923  					Currency: "USD",
   924  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   925  						{
   926  							ModelVersion: "model 1 from req",
   927  							Currency:     "USD",
   928  							Values: map[string]float64{
   929  								"banner|300x600|www.website5.com": 5,
   930  								"*|*|*":                           7,
   931  							},
   932  							Schema: openrtb_ext.PriceFloorSchema{
   933  								Fields:    []string{"mediaType", "size", "domain"},
   934  								Delimiter: "|",
   935  							},
   936  						},
   937  					},
   938  				},
   939  			},
   940  		},
   941  		{
   942  			name:    "Dynamic fetch enabled, floors from fetched selected as data rate is 100",
   943  			fetcher: &MockFetchDataRate100{},
   944  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   945  				BidRequest: &openrtb2.BidRequest{
   946  					Site: &openrtb2.Site{
   947  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   948  					},
   949  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   950  				},
   951  			},
   952  			account: config.Account{
   953  				PriceFloors: config.AccountPriceFloors{
   954  					Enabled:        true,
   955  					UseDynamicData: true,
   956  				},
   957  			},
   958  			expFloors: &openrtb_ext.PriceFloorRules{
   959  				Enabled:            getTrue(),
   960  				FetchStatus:        openrtb_ext.FetchSuccess,
   961  				PriceFloorLocation: openrtb_ext.FetchLocation,
   962  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
   963  					EnforcePBS:  getTrue(),
   964  					FloorDeals:  getTrue(),
   965  					EnforceRate: 100,
   966  				},
   967  				Data: &openrtb_ext.PriceFloorData{
   968  					Currency: "USD",
   969  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
   970  						{
   971  							ModelVersion: "model from fetched",
   972  							Currency:     "USD",
   973  							Values: map[string]float64{
   974  								"banner|300x600|www.website5.com": 15,
   975  								"*|*|*":                           25,
   976  							},
   977  							Schema: openrtb_ext.PriceFloorSchema{
   978  								Fields: []string{"mediaType", "size", "domain"},
   979  							},
   980  						},
   981  					},
   982  					FetchRate: ptrutil.ToPtr(100),
   983  				},
   984  			},
   985  		},
   986  		{
   987  			name:    "Dynamic fetch enabled, floors from fetched selected as data rate not provided as default value = 100",
   988  			fetcher: &MockFetchDataRateNotProvided{},
   989  			bidRequestWrapper: &openrtb_ext.RequestWrapper{
   990  				BidRequest: &openrtb2.BidRequest{
   991  					Site: &openrtb2.Site{
   992  						Publisher: &openrtb2.Publisher{Domain: "www.website.com"},
   993  					},
   994  					Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}},
   995  					Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`),
   996  				},
   997  			},
   998  			account: config.Account{
   999  				PriceFloors: config.AccountPriceFloors{
  1000  					Enabled:        true,
  1001  					UseDynamicData: true,
  1002  				},
  1003  			},
  1004  			expFloors: &openrtb_ext.PriceFloorRules{
  1005  				Enabled:            getTrue(),
  1006  				FetchStatus:        openrtb_ext.FetchSuccess,
  1007  				PriceFloorLocation: openrtb_ext.FetchLocation,
  1008  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1009  					EnforcePBS:  getTrue(),
  1010  					FloorDeals:  getTrue(),
  1011  					EnforceRate: 100,
  1012  				},
  1013  				Data: &openrtb_ext.PriceFloorData{
  1014  					Currency: "USD",
  1015  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1016  						{
  1017  							ModelVersion: "model from fetched",
  1018  							Currency:     "USD",
  1019  							Values: map[string]float64{
  1020  								"banner|300x600|www.website5.com": 5,
  1021  								"*|*|*":                           15,
  1022  							},
  1023  							Schema: openrtb_ext.PriceFloorSchema{
  1024  								Fields: []string{"mediaType", "size", "domain"},
  1025  							},
  1026  						},
  1027  					},
  1028  				},
  1029  			},
  1030  		},
  1031  	}
  1032  
  1033  	for _, tc := range testCases {
  1034  		t.Run(tc.name, func(t *testing.T) {
  1035  			resolvedFloors, _ := resolveFloors(tc.account, tc.bidRequestWrapper, getCurrencyRates(rates), tc.fetcher)
  1036  			assert.Equal(t, resolvedFloors, tc.expFloors, tc.name)
  1037  		})
  1038  	}
  1039  }
  1040  
  1041  func printFloors(floors *openrtb_ext.PriceFloorRules) string {
  1042  	fbytes, _ := jsonutil.Marshal(floors)
  1043  	return string(fbytes)
  1044  }
  1045  
  1046  func TestCreateFloorsFrom(t *testing.T) {
  1047  
  1048  	testAccountConfig := config.Account{
  1049  		PriceFloors: config.AccountPriceFloors{
  1050  			Enabled:        true,
  1051  			UseDynamicData: false,
  1052  			MaxRule:        100,
  1053  			MaxSchemaDims:  5,
  1054  		},
  1055  	}
  1056  
  1057  	type args struct {
  1058  		floors        *openrtb_ext.PriceFloorRules
  1059  		account       config.Account
  1060  		fetchStatus   string
  1061  		floorLocation string
  1062  	}
  1063  	testCases := []struct {
  1064  		name  string
  1065  		args  args
  1066  		want  *openrtb_ext.PriceFloorRules
  1067  		want1 []error
  1068  	}{
  1069  		{
  1070  			name: "floor provider should be selected from floor json",
  1071  			args: args{
  1072  				account: testAccountConfig,
  1073  				floors: &openrtb_ext.PriceFloorRules{
  1074  					Enabled:     getTrue(),
  1075  					FloorMin:    10.11,
  1076  					FloorMinCur: "EUR",
  1077  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1078  						EnforcePBS:  getTrue(),
  1079  						EnforceRate: 100,
  1080  						FloorDeals:  getTrue(),
  1081  					},
  1082  					Data: &openrtb_ext.PriceFloorData{
  1083  						Currency: "USD",
  1084  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1085  							{
  1086  								ModelVersion: "model from fetched",
  1087  								Currency:     "USD",
  1088  								Values: map[string]float64{
  1089  									"banner|300x600|www.website5.com": 15,
  1090  									"*|*|*":                           25,
  1091  								},
  1092  								Schema: openrtb_ext.PriceFloorSchema{
  1093  									Fields: []string{"mediaType", "size", "domain"},
  1094  								},
  1095  							},
  1096  						},
  1097  						FloorProvider: "PM",
  1098  					},
  1099  				},
  1100  				fetchStatus:   openrtb_ext.FetchSuccess,
  1101  				floorLocation: openrtb_ext.FetchLocation,
  1102  			},
  1103  			want: &openrtb_ext.PriceFloorRules{
  1104  				Enabled:            getTrue(),
  1105  				FloorMin:           10.11,
  1106  				FloorMinCur:        "EUR",
  1107  				FetchStatus:        openrtb_ext.FetchSuccess,
  1108  				PriceFloorLocation: openrtb_ext.FetchLocation,
  1109  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1110  					EnforcePBS:  getTrue(),
  1111  					EnforceRate: 100,
  1112  					FloorDeals:  getTrue(),
  1113  				},
  1114  				Data: &openrtb_ext.PriceFloorData{
  1115  					Currency: "USD",
  1116  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1117  						{
  1118  							ModelVersion: "model from fetched",
  1119  							Currency:     "USD",
  1120  							Values: map[string]float64{
  1121  								"banner|300x600|www.website5.com": 15,
  1122  								"*|*|*":                           25,
  1123  							},
  1124  							Schema: openrtb_ext.PriceFloorSchema{
  1125  								Fields: []string{"mediaType", "size", "domain"},
  1126  							},
  1127  						},
  1128  					},
  1129  					FloorProvider: "PM",
  1130  				},
  1131  			},
  1132  		},
  1133  		{
  1134  			name: "floor provider will be empty if no value provided in floor json",
  1135  			args: args{
  1136  				account: testAccountConfig,
  1137  				floors: &openrtb_ext.PriceFloorRules{
  1138  					Enabled:     getTrue(),
  1139  					FloorMin:    10.11,
  1140  					FloorMinCur: "EUR",
  1141  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1142  						EnforcePBS:  getTrue(),
  1143  						EnforceRate: 100,
  1144  						FloorDeals:  getTrue(),
  1145  					},
  1146  					Data: &openrtb_ext.PriceFloorData{
  1147  						Currency: "USD",
  1148  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1149  							{
  1150  								ModelVersion: "model from request",
  1151  								Currency:     "USD",
  1152  								Values: map[string]float64{
  1153  									"banner|300x600|www.website5.com": 15,
  1154  									"*|*|*":                           25,
  1155  								},
  1156  								Schema: openrtb_ext.PriceFloorSchema{
  1157  									Fields: []string{"mediaType", "size", "domain"},
  1158  								},
  1159  							},
  1160  						},
  1161  						FloorProvider: "",
  1162  					},
  1163  				},
  1164  				fetchStatus:   openrtb_ext.FetchSuccess,
  1165  				floorLocation: openrtb_ext.FetchLocation,
  1166  			},
  1167  			want: &openrtb_ext.PriceFloorRules{
  1168  				Enabled:            getTrue(),
  1169  				FloorMin:           10.11,
  1170  				FloorMinCur:        "EUR",
  1171  				FetchStatus:        openrtb_ext.FetchSuccess,
  1172  				PriceFloorLocation: openrtb_ext.FetchLocation,
  1173  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1174  					EnforcePBS:  getTrue(),
  1175  					EnforceRate: 100,
  1176  					FloorDeals:  getTrue(),
  1177  				},
  1178  				Data: &openrtb_ext.PriceFloorData{
  1179  					Currency: "USD",
  1180  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1181  						{
  1182  							ModelVersion: "model from request",
  1183  							Currency:     "USD",
  1184  							Values: map[string]float64{
  1185  								"banner|300x600|www.website5.com": 15,
  1186  								"*|*|*":                           25,
  1187  							},
  1188  							Schema: openrtb_ext.PriceFloorSchema{
  1189  								Fields: []string{"mediaType", "size", "domain"},
  1190  							},
  1191  						},
  1192  					},
  1193  					FloorProvider: "",
  1194  				},
  1195  			},
  1196  		},
  1197  		{
  1198  			name: "only floor enforcement object present",
  1199  			args: args{
  1200  				account: testAccountConfig,
  1201  				floors: &openrtb_ext.PriceFloorRules{
  1202  					Enabled: getTrue(),
  1203  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1204  						EnforcePBS:  getTrue(),
  1205  						EnforceRate: 100,
  1206  						FloorDeals:  getTrue(),
  1207  					},
  1208  				},
  1209  				fetchStatus:   openrtb_ext.FetchNone,
  1210  				floorLocation: openrtb_ext.RequestLocation,
  1211  			},
  1212  			want: &openrtb_ext.PriceFloorRules{
  1213  				FetchStatus:        openrtb_ext.FetchNone,
  1214  				PriceFloorLocation: openrtb_ext.RequestLocation,
  1215  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1216  					EnforcePBS:  getTrue(),
  1217  					EnforceRate: 100,
  1218  					FloorDeals:  getTrue(),
  1219  				},
  1220  			},
  1221  		},
  1222  		{
  1223  			name: "Invalid modelGroup with skipRate = 110",
  1224  			args: args{
  1225  				account: testAccountConfig,
  1226  				floors: &openrtb_ext.PriceFloorRules{
  1227  					Enabled: getTrue(),
  1228  					Data: &openrtb_ext.PriceFloorData{
  1229  						Currency: "USD",
  1230  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1231  							{
  1232  								ModelVersion: "model from fetched",
  1233  								Currency:     "USD",
  1234  								SkipRate:     110,
  1235  								Values: map[string]float64{
  1236  									"banner|300x600|www.website5.com": 15,
  1237  									"*|*|*":                           25,
  1238  								},
  1239  								Schema: openrtb_ext.PriceFloorSchema{
  1240  									Fields: []string{"mediaType", "size", "domain"},
  1241  								},
  1242  							},
  1243  						},
  1244  					},
  1245  				},
  1246  				fetchStatus:   openrtb_ext.FetchNone,
  1247  				floorLocation: openrtb_ext.RequestLocation,
  1248  			},
  1249  			want: &openrtb_ext.PriceFloorRules{
  1250  				FetchStatus:        openrtb_ext.FetchNone,
  1251  				PriceFloorLocation: openrtb_ext.RequestLocation,
  1252  			},
  1253  			want1: []error{
  1254  				errors.New("Invalid Floor Model = 'model from fetched' due to SkipRate = '110' is out of range (1-100)"),
  1255  			},
  1256  		},
  1257  	}
  1258  	for _, tc := range testCases {
  1259  		t.Run(tc.name, func(t *testing.T) {
  1260  			got, got1 := createFloorsFrom(tc.args.floors, tc.args.account, tc.args.fetchStatus, tc.args.floorLocation)
  1261  			assert.Equal(t, got1, tc.want1, tc.name)
  1262  			assert.Equal(t, got, tc.want, tc.name)
  1263  		})
  1264  	}
  1265  }
  1266  
  1267  func TestIsPriceFloorsEnabled(t *testing.T) {
  1268  	type args struct {
  1269  		account           config.Account
  1270  		bidRequestWrapper *openrtb_ext.RequestWrapper
  1271  	}
  1272  	tests := []struct {
  1273  		name string
  1274  		args args
  1275  		want bool
  1276  	}{
  1277  		{
  1278  			name: "Disabled in account and req",
  1279  			args: args{
  1280  				account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: false}},
  1281  				bidRequestWrapper: &openrtb_ext.RequestWrapper{
  1282  					BidRequest: &openrtb2.BidRequest{
  1283  						Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": false} }}`),
  1284  					},
  1285  				},
  1286  			},
  1287  			want: false,
  1288  		},
  1289  		{
  1290  			name: "Enabled  in account and req",
  1291  			args: args{
  1292  				account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: true}},
  1293  				bidRequestWrapper: &openrtb_ext.RequestWrapper{
  1294  					BidRequest: &openrtb2.BidRequest{
  1295  						Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": true} }}`),
  1296  					},
  1297  				},
  1298  			},
  1299  			want: true,
  1300  		},
  1301  		{
  1302  			name: "disabled  in account and enabled req",
  1303  			args: args{
  1304  				account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: false}},
  1305  				bidRequestWrapper: &openrtb_ext.RequestWrapper{
  1306  					BidRequest: &openrtb2.BidRequest{
  1307  						Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": true} }}`),
  1308  					},
  1309  				},
  1310  			},
  1311  			want: false,
  1312  		},
  1313  		{
  1314  			name: "Enabled  in account and disabled in req",
  1315  			args: args{
  1316  				account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: true}},
  1317  				bidRequestWrapper: &openrtb_ext.RequestWrapper{
  1318  					BidRequest: &openrtb2.BidRequest{
  1319  						Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": false} }}`)},
  1320  				},
  1321  			},
  1322  			want: false,
  1323  		},
  1324  	}
  1325  	for _, tt := range tests {
  1326  		t.Run(tt.name, func(t *testing.T) {
  1327  			got := isPriceFloorsEnabled(tt.args.account, tt.args.bidRequestWrapper)
  1328  			assert.Equal(t, got, tt.want, tt.name)
  1329  		})
  1330  	}
  1331  }
  1332  
  1333  func TestResolveFloorMin(t *testing.T) {
  1334  	rates := map[string]map[string]float64{
  1335  		"USD": {
  1336  			"INR": 70,
  1337  			"EUR": 0.9,
  1338  			"JPY": 5.09,
  1339  		},
  1340  	}
  1341  
  1342  	tt := []struct {
  1343  		name        string
  1344  		reqFloors   openrtb_ext.PriceFloorRules
  1345  		fetchFloors openrtb_ext.PriceFloorRules
  1346  		conversions currency.Conversions
  1347  		expPrice    Price
  1348  	}{
  1349  		{
  1350  			name: "FloorsMin present in request Floors only",
  1351  			reqFloors: openrtb_ext.PriceFloorRules{
  1352  				FloorMin:    10,
  1353  				FloorMinCur: "JPY",
  1354  			},
  1355  			fetchFloors: openrtb_ext.PriceFloorRules{},
  1356  			expPrice:    Price{FloorMin: 10, FloorMinCur: "JPY"},
  1357  		},
  1358  		{
  1359  			name: "FloorsMin, FloorMinCur and data currency present in request Floors",
  1360  			reqFloors: openrtb_ext.PriceFloorRules{
  1361  				FloorMin:    10,
  1362  				FloorMinCur: "JPY",
  1363  				Data: &openrtb_ext.PriceFloorData{
  1364  					Currency: "USD",
  1365  				},
  1366  			},
  1367  			fetchFloors: openrtb_ext.PriceFloorRules{},
  1368  			expPrice:    Price{FloorMin: 10, FloorMinCur: "JPY"},
  1369  		},
  1370  		{
  1371  			name: "FloorsMin and data currency present in request Floors",
  1372  			reqFloors: openrtb_ext.PriceFloorRules{
  1373  				FloorMin: 10,
  1374  				Data: &openrtb_ext.PriceFloorData{
  1375  					Currency: "USD",
  1376  				},
  1377  			},
  1378  			fetchFloors: openrtb_ext.PriceFloorRules{},
  1379  			expPrice:    Price{FloorMin: 10, FloorMinCur: "USD"},
  1380  		},
  1381  		{
  1382  			name: "FloorsMin and FloorMinCur present in request Floors and fetched floors",
  1383  			reqFloors: openrtb_ext.PriceFloorRules{
  1384  				FloorMin:    10,
  1385  				FloorMinCur: "USD",
  1386  			},
  1387  			fetchFloors: openrtb_ext.PriceFloorRules{
  1388  				FloorMin:    15,
  1389  				FloorMinCur: "INR",
  1390  			},
  1391  			expPrice: Price{FloorMin: 10, FloorMinCur: "USD"},
  1392  		},
  1393  		{
  1394  			name:      "FloorsMin present fetched floors only",
  1395  			reqFloors: openrtb_ext.PriceFloorRules{},
  1396  			fetchFloors: openrtb_ext.PriceFloorRules{
  1397  				FloorMin:    15,
  1398  				FloorMinCur: "EUR",
  1399  			},
  1400  			expPrice: Price{FloorMin: 15, FloorMinCur: "EUR"},
  1401  		},
  1402  		{
  1403  			name: "FloorMinCur present in reqFloors And FloorsMin, FloorMinCur present in fetched floors (Same Currency)",
  1404  			reqFloors: openrtb_ext.PriceFloorRules{
  1405  				FloorMinCur: "EUR",
  1406  			},
  1407  			fetchFloors: openrtb_ext.PriceFloorRules{
  1408  				FloorMin:    15,
  1409  				FloorMinCur: "EUR",
  1410  			},
  1411  			expPrice: Price{FloorMin: 15, FloorMinCur: "EUR"},
  1412  		},
  1413  		{
  1414  			name: "FloorMinCur present in reqFloors And FloorsMin, FloorMinCur present in fetched floors (Different Currency)",
  1415  			reqFloors: openrtb_ext.PriceFloorRules{
  1416  				FloorMinCur: "USD",
  1417  			},
  1418  			fetchFloors: openrtb_ext.PriceFloorRules{
  1419  				FloorMin:    15,
  1420  				FloorMinCur: "EUR",
  1421  			},
  1422  			expPrice: Price{FloorMin: 16.6667, FloorMinCur: "USD"},
  1423  		},
  1424  		{
  1425  			name: "FloorMin present in reqFloors And FloorMinCur present in fetched floors",
  1426  			reqFloors: openrtb_ext.PriceFloorRules{
  1427  				FloorMin: 11,
  1428  			},
  1429  			fetchFloors: openrtb_ext.PriceFloorRules{
  1430  				FloorMinCur: "EUR",
  1431  			},
  1432  			expPrice: Price{FloorMin: 11, FloorMinCur: "EUR"},
  1433  		},
  1434  		{
  1435  			name: "FloorMinCur present in reqFloors And FloorMin present in fetched floors",
  1436  			reqFloors: openrtb_ext.PriceFloorRules{
  1437  				FloorMinCur: "INR",
  1438  			},
  1439  			fetchFloors: openrtb_ext.PriceFloorRules{
  1440  				FloorMin: 12,
  1441  			},
  1442  			expPrice: Price{FloorMin: 12, FloorMinCur: "INR"},
  1443  		},
  1444  		{
  1445  			name: "FloorMinCur present in reqFloors And FloorMin, data currency present in fetched floors",
  1446  			reqFloors: openrtb_ext.PriceFloorRules{
  1447  				FloorMinCur: "INR",
  1448  			},
  1449  			fetchFloors: openrtb_ext.PriceFloorRules{
  1450  				FloorMin: 1,
  1451  				Data:     &openrtb_ext.PriceFloorData{Currency: "USD"},
  1452  			},
  1453  			expPrice: Price{FloorMin: 70, FloorMinCur: "INR"},
  1454  		},
  1455  		{
  1456  			name: "FloorMinCur present in fetched Floors And data currency present in reqFloors",
  1457  			reqFloors: openrtb_ext.PriceFloorRules{
  1458  				FloorMin: 2,
  1459  			},
  1460  			fetchFloors: openrtb_ext.PriceFloorRules{
  1461  				Data: &openrtb_ext.PriceFloorData{Currency: "USD"},
  1462  			},
  1463  			expPrice: Price{FloorMin: 2, FloorMinCur: "USD"},
  1464  		},
  1465  		{
  1466  			name:      "Data currency and FloorMin present in fetched floors",
  1467  			reqFloors: openrtb_ext.PriceFloorRules{},
  1468  			fetchFloors: openrtb_ext.PriceFloorRules{
  1469  				FloorMin: 12,
  1470  				Data:     &openrtb_ext.PriceFloorData{Currency: "USD"},
  1471  			},
  1472  			expPrice: Price{FloorMin: 12, FloorMinCur: "USD"},
  1473  		},
  1474  		{
  1475  			name:        "Empty reqFloors And Empty fetched floors",
  1476  			reqFloors:   openrtb_ext.PriceFloorRules{},
  1477  			fetchFloors: openrtb_ext.PriceFloorRules{},
  1478  			expPrice:    Price{FloorMin: 0.0, FloorMinCur: ""},
  1479  		},
  1480  	}
  1481  	for _, tc := range tt {
  1482  		t.Run(tc.name, func(t *testing.T) {
  1483  			price := resolveFloorMin(&tc.reqFloors, &tc.fetchFloors, getCurrencyRates(rates))
  1484  			if !reflect.DeepEqual(price.FloorMin, tc.expPrice.FloorMin) {
  1485  				t.Errorf("Floor Value error: \nreturn:\t%v\nwant:\t%v", price.FloorMin, tc.expPrice.FloorMin)
  1486  			}
  1487  			if !reflect.DeepEqual(price.FloorMinCur, tc.expPrice.FloorMinCur) {
  1488  				t.Errorf("Floor Currency error: \nreturn:\t%v\nwant:\t%v", price.FloorMinCur, tc.expPrice.FloorMinCur)
  1489  			}
  1490  
  1491  		})
  1492  	}
  1493  }
  1494  
  1495  func TestMergeFloors(t *testing.T) {
  1496  
  1497  	rates := map[string]map[string]float64{
  1498  		"USD": {
  1499  			"INR": 70,
  1500  			"EUR": 0.9,
  1501  			"JPY": 5.09,
  1502  		},
  1503  	}
  1504  
  1505  	type args struct {
  1506  		reqFloors   *openrtb_ext.PriceFloorRules
  1507  		fetchFloors *openrtb_ext.PriceFloorRules
  1508  	}
  1509  	tests := []struct {
  1510  		name string
  1511  		args args
  1512  		want *openrtb_ext.PriceFloorRules
  1513  	}{
  1514  		{
  1515  			name: "Fetched Floors are present and request Floors are empty",
  1516  			args: args{
  1517  				reqFloors: nil,
  1518  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1519  					Enabled: getTrue(),
  1520  					Data: &openrtb_ext.PriceFloorData{
  1521  						Currency: "INR",
  1522  						SkipRate: 0,
  1523  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1524  							{
  1525  								ModelVersion: "Version 1",
  1526  								Currency:     "INR",
  1527  								Values: map[string]float64{
  1528  									"banner|300x600|www.website5.com": 20,
  1529  									"*|*|*":                           50,
  1530  								},
  1531  								Schema: openrtb_ext.PriceFloorSchema{
  1532  									Fields:    []string{"mediaType", "size", "domain"},
  1533  									Delimiter: "|",
  1534  								},
  1535  							},
  1536  						},
  1537  					},
  1538  				},
  1539  			},
  1540  			want: &openrtb_ext.PriceFloorRules{
  1541  				Enabled: getTrue(),
  1542  				Data: &openrtb_ext.PriceFloorData{
  1543  					Currency: "INR",
  1544  					SkipRate: 0,
  1545  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1546  						{
  1547  							ModelVersion: "Version 1",
  1548  							Currency:     "INR",
  1549  							Values: map[string]float64{
  1550  								"banner|300x600|www.website5.com": 20,
  1551  								"*|*|*":                           50,
  1552  							},
  1553  							Schema: openrtb_ext.PriceFloorSchema{
  1554  								Fields:    []string{"mediaType", "size", "domain"},
  1555  								Delimiter: "|",
  1556  							},
  1557  						},
  1558  					},
  1559  				},
  1560  			},
  1561  		},
  1562  		{
  1563  			name: "Fetched Floors are present and request Floors has floors disabled",
  1564  			args: args{
  1565  				reqFloors: &openrtb_ext.PriceFloorRules{
  1566  					Enabled: getFalse(),
  1567  				},
  1568  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1569  					Enabled: getTrue(),
  1570  					Data: &openrtb_ext.PriceFloorData{
  1571  						Currency: "INR",
  1572  						SkipRate: 0,
  1573  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1574  							{
  1575  								ModelVersion: "Version 1",
  1576  								Currency:     "INR",
  1577  								Values: map[string]float64{
  1578  									"banner|300x600|www.website5.com": 20,
  1579  									"*|*|*":                           50,
  1580  								},
  1581  								Schema: openrtb_ext.PriceFloorSchema{
  1582  									Fields:    []string{"mediaType", "size", "domain"},
  1583  									Delimiter: "|",
  1584  								},
  1585  							},
  1586  						},
  1587  					},
  1588  				},
  1589  			},
  1590  			want: &openrtb_ext.PriceFloorRules{
  1591  				Enabled: getFalse(),
  1592  				Data: &openrtb_ext.PriceFloorData{
  1593  					Currency: "INR",
  1594  					SkipRate: 0,
  1595  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1596  						{
  1597  							ModelVersion: "Version 1",
  1598  							Currency:     "INR",
  1599  							Values: map[string]float64{
  1600  								"banner|300x600|www.website5.com": 20,
  1601  								"*|*|*":                           50,
  1602  							},
  1603  							Schema: openrtb_ext.PriceFloorSchema{
  1604  								Fields:    []string{"mediaType", "size", "domain"},
  1605  								Delimiter: "|",
  1606  							},
  1607  						},
  1608  					},
  1609  				},
  1610  			},
  1611  		},
  1612  		{
  1613  			name: "Fetched Floors are present and request Floors has enforcement (enforcepbs = true)",
  1614  			args: args{
  1615  				reqFloors: &openrtb_ext.PriceFloorRules{
  1616  					Enabled: getTrue(),
  1617  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1618  						EnforceRate: 50,
  1619  						EnforcePBS:  getTrue(),
  1620  					},
  1621  				},
  1622  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1623  					Enabled: getTrue(),
  1624  					Data: &openrtb_ext.PriceFloorData{
  1625  						Currency: "INR",
  1626  						SkipRate: 0,
  1627  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1628  							{
  1629  								ModelVersion: "Version 1",
  1630  								Currency:     "INR",
  1631  								Values: map[string]float64{
  1632  									"banner|300x600|www.website5.com": 20,
  1633  									"*|*|*":                           50,
  1634  								},
  1635  								Schema: openrtb_ext.PriceFloorSchema{
  1636  									Fields:    []string{"mediaType", "size", "domain"},
  1637  									Delimiter: "|",
  1638  								},
  1639  							},
  1640  						},
  1641  					},
  1642  				},
  1643  			},
  1644  			want: &openrtb_ext.PriceFloorRules{
  1645  				Enabled: getTrue(),
  1646  				Data: &openrtb_ext.PriceFloorData{
  1647  					Currency: "INR",
  1648  					SkipRate: 0,
  1649  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1650  						{
  1651  							ModelVersion: "Version 1",
  1652  							Currency:     "INR",
  1653  							Values: map[string]float64{
  1654  								"banner|300x600|www.website5.com": 20,
  1655  								"*|*|*":                           50,
  1656  							},
  1657  							Schema: openrtb_ext.PriceFloorSchema{
  1658  								Fields:    []string{"mediaType", "size", "domain"},
  1659  								Delimiter: "|",
  1660  							},
  1661  						},
  1662  					},
  1663  				},
  1664  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1665  					EnforceRate: 50,
  1666  					EnforcePBS:  getTrue(),
  1667  				},
  1668  			},
  1669  		},
  1670  		{
  1671  			name: "Fetched Floors are present and request Floors has enforcement (enforcepbs = false)",
  1672  			args: args{
  1673  				reqFloors: &openrtb_ext.PriceFloorRules{
  1674  					Enabled: getTrue(),
  1675  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1676  						EnforceRate: 50,
  1677  						EnforcePBS:  getFalse(),
  1678  					},
  1679  				},
  1680  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1681  					Enabled: getTrue(),
  1682  					Data: &openrtb_ext.PriceFloorData{
  1683  						Currency: "INR",
  1684  						SkipRate: 0,
  1685  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1686  							{
  1687  								ModelVersion: "Version 1",
  1688  								Currency:     "INR",
  1689  								Values: map[string]float64{
  1690  									"banner|300x600|www.website5.com": 20,
  1691  									"*|*|*":                           50,
  1692  								},
  1693  								Schema: openrtb_ext.PriceFloorSchema{
  1694  									Fields:    []string{"mediaType", "size", "domain"},
  1695  									Delimiter: "|",
  1696  								},
  1697  							},
  1698  						},
  1699  					},
  1700  				},
  1701  			},
  1702  			want: &openrtb_ext.PriceFloorRules{
  1703  				Enabled: getTrue(),
  1704  				Data: &openrtb_ext.PriceFloorData{
  1705  					Currency: "INR",
  1706  					SkipRate: 0,
  1707  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1708  						{
  1709  							ModelVersion: "Version 1",
  1710  							Currency:     "INR",
  1711  							Values: map[string]float64{
  1712  								"banner|300x600|www.website5.com": 20,
  1713  								"*|*|*":                           50,
  1714  							},
  1715  							Schema: openrtb_ext.PriceFloorSchema{
  1716  								Fields:    []string{"mediaType", "size", "domain"},
  1717  								Delimiter: "|",
  1718  							},
  1719  						},
  1720  					},
  1721  				},
  1722  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1723  					EnforceRate: 50,
  1724  					EnforcePBS:  getFalse(),
  1725  				},
  1726  			},
  1727  		},
  1728  		{
  1729  			name: "Fetched Floors are present and request Floors has Floormin",
  1730  			args: args{
  1731  				reqFloors: &openrtb_ext.PriceFloorRules{
  1732  					Enabled: getTrue(),
  1733  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1734  						EnforceRate: 50,
  1735  						EnforcePBS:  getFalse(),
  1736  					},
  1737  					FloorMin:    5,
  1738  					FloorMinCur: "INR",
  1739  				},
  1740  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1741  					Enabled: getTrue(),
  1742  					Data: &openrtb_ext.PriceFloorData{
  1743  						Currency: "INR",
  1744  						SkipRate: 0,
  1745  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1746  							{
  1747  								ModelVersion: "Version 1",
  1748  								Currency:     "INR",
  1749  								Values: map[string]float64{
  1750  									"banner|300x600|www.website5.com": 20,
  1751  									"*|*|*":                           50,
  1752  								},
  1753  								Schema: openrtb_ext.PriceFloorSchema{
  1754  									Fields:    []string{"mediaType", "size", "domain"},
  1755  									Delimiter: "|",
  1756  								},
  1757  							},
  1758  						},
  1759  					},
  1760  				},
  1761  			},
  1762  			want: &openrtb_ext.PriceFloorRules{
  1763  				Enabled: getTrue(),
  1764  				Data: &openrtb_ext.PriceFloorData{
  1765  					Currency: "INR",
  1766  					SkipRate: 0,
  1767  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1768  						{
  1769  							ModelVersion: "Version 1",
  1770  							Currency:     "INR",
  1771  							Values: map[string]float64{
  1772  								"banner|300x600|www.website5.com": 20,
  1773  								"*|*|*":                           50,
  1774  							},
  1775  							Schema: openrtb_ext.PriceFloorSchema{
  1776  								Fields:    []string{"mediaType", "size", "domain"},
  1777  								Delimiter: "|",
  1778  							},
  1779  						},
  1780  					},
  1781  				},
  1782  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1783  					EnforceRate: 50,
  1784  					EnforcePBS:  getFalse(),
  1785  				},
  1786  				FloorMin:    5,
  1787  				FloorMinCur: "INR",
  1788  			},
  1789  		},
  1790  		{
  1791  			name: "Fetched Floors are present and request Floors has URL",
  1792  			args: args{
  1793  				reqFloors: &openrtb_ext.PriceFloorRules{
  1794  					Enabled: getTrue(),
  1795  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1796  						EnforceRate: 50,
  1797  						EnforcePBS:  getFalse(),
  1798  					},
  1799  					FloorMin:    5,
  1800  					FloorMinCur: "INR",
  1801  					Location: &openrtb_ext.PriceFloorEndpoint{
  1802  						URL: "https://test.com/floors",
  1803  					},
  1804  				},
  1805  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1806  					Enabled: getTrue(),
  1807  					Data: &openrtb_ext.PriceFloorData{
  1808  						Currency: "INR",
  1809  						SkipRate: 0,
  1810  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1811  							{
  1812  								ModelVersion: "Version 1",
  1813  								Currency:     "INR",
  1814  								Values: map[string]float64{
  1815  									"banner|300x600|www.website5.com": 20,
  1816  									"*|*|*":                           50,
  1817  								},
  1818  								Schema: openrtb_ext.PriceFloorSchema{
  1819  									Fields:    []string{"mediaType", "size", "domain"},
  1820  									Delimiter: "|",
  1821  								},
  1822  							},
  1823  						},
  1824  					},
  1825  				},
  1826  			},
  1827  			want: &openrtb_ext.PriceFloorRules{
  1828  				Enabled: getTrue(),
  1829  				Data: &openrtb_ext.PriceFloorData{
  1830  					Currency: "INR",
  1831  					SkipRate: 0,
  1832  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1833  						{
  1834  							ModelVersion: "Version 1",
  1835  							Currency:     "INR",
  1836  							Values: map[string]float64{
  1837  								"banner|300x600|www.website5.com": 20,
  1838  								"*|*|*":                           50,
  1839  							},
  1840  							Schema: openrtb_ext.PriceFloorSchema{
  1841  								Fields:    []string{"mediaType", "size", "domain"},
  1842  								Delimiter: "|",
  1843  							},
  1844  						},
  1845  					},
  1846  				},
  1847  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1848  					EnforceRate: 50,
  1849  					EnforcePBS:  getFalse(),
  1850  				},
  1851  				FloorMin:    5,
  1852  				FloorMinCur: "INR",
  1853  				Location: &openrtb_ext.PriceFloorEndpoint{
  1854  					URL: "https://test.com/floors",
  1855  				},
  1856  			},
  1857  		},
  1858  		{
  1859  			name: "Fetched Floors has no enable atrribute are present and request Floors has URL",
  1860  			args: args{
  1861  				reqFloors: &openrtb_ext.PriceFloorRules{
  1862  					Enabled: getTrue(),
  1863  					Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1864  						EnforceRate: 50,
  1865  						EnforcePBS:  getFalse(),
  1866  					},
  1867  					FloorMin:    5,
  1868  					FloorMinCur: "INR",
  1869  					Location: &openrtb_ext.PriceFloorEndpoint{
  1870  						URL: "https://test.com/floors",
  1871  					},
  1872  				},
  1873  				fetchFloors: &openrtb_ext.PriceFloorRules{
  1874  					Data: &openrtb_ext.PriceFloorData{
  1875  						Currency: "INR",
  1876  						SkipRate: 0,
  1877  						ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1878  							{
  1879  								ModelVersion: "Version 1",
  1880  								Currency:     "INR",
  1881  								Values: map[string]float64{
  1882  									"banner|300x600|www.website5.com": 20,
  1883  									"*|*|*":                           50,
  1884  								},
  1885  								Schema: openrtb_ext.PriceFloorSchema{
  1886  									Fields:    []string{"mediaType", "size", "domain"},
  1887  									Delimiter: "|",
  1888  								},
  1889  							},
  1890  						},
  1891  					},
  1892  				},
  1893  			},
  1894  			want: &openrtb_ext.PriceFloorRules{
  1895  				Enabled: getTrue(),
  1896  				Data: &openrtb_ext.PriceFloorData{
  1897  					Currency: "INR",
  1898  					SkipRate: 0,
  1899  					ModelGroups: []openrtb_ext.PriceFloorModelGroup{
  1900  						{
  1901  							ModelVersion: "Version 1",
  1902  							Currency:     "INR",
  1903  							Values: map[string]float64{
  1904  								"banner|300x600|www.website5.com": 20,
  1905  								"*|*|*":                           50,
  1906  							},
  1907  							Schema: openrtb_ext.PriceFloorSchema{
  1908  								Fields:    []string{"mediaType", "size", "domain"},
  1909  								Delimiter: "|",
  1910  							},
  1911  						},
  1912  					},
  1913  				},
  1914  				Enforcement: &openrtb_ext.PriceFloorEnforcement{
  1915  					EnforceRate: 50,
  1916  					EnforcePBS:  getFalse(),
  1917  				},
  1918  				FloorMin:    5,
  1919  				FloorMinCur: "INR",
  1920  				Location: &openrtb_ext.PriceFloorEndpoint{
  1921  					URL: "https://test.com/floors",
  1922  				},
  1923  			},
  1924  		},
  1925  	}
  1926  	for _, tt := range tests {
  1927  		t.Run(tt.name, func(t *testing.T) {
  1928  			if got := mergeFloors(tt.args.reqFloors, tt.args.fetchFloors, getCurrencyRates(rates)); !reflect.DeepEqual(got, tt.want) {
  1929  				t.Errorf("mergeFloors() = %v, want %v", got, tt.want)
  1930  			}
  1931  		})
  1932  	}
  1933  }