github.com/prebid/prebid-server@v0.275.0/floors/validate_test.go (about)

     1  package floors
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/prebid/prebid-server/config"
     9  	"github.com/prebid/prebid-server/openrtb_ext"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestValidateFloorParams(t *testing.T) {
    14  
    15  	tt := []struct {
    16  		name     string
    17  		floorExt *openrtb_ext.PriceFloorRules
    18  		Err      error
    19  	}{
    20  		{
    21  			name: "Valid Skip Rate",
    22  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
    23  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
    24  					ModelVersion: "Version 1",
    25  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}, Delimiter: "|"},
    26  					Values: map[string]float64{
    27  						"banner|300x250|www.website.com":              1.01,
    28  						"banner|300x250|*":                            2.01,
    29  						"banner|300x600|www.website.com|www.test.com": 3.01,
    30  						"banner|300x600|*":                            4.01,
    31  					}, Default: 0.01},
    32  				}}},
    33  		},
    34  		{
    35  			name:     "Invalid Skip Rate at Root level",
    36  			floorExt: &openrtb_ext.PriceFloorRules{SkipRate: -10},
    37  			Err:      errors.New("Invalid SkipRate = '-10' at ext.prebid.floors.skiprate"),
    38  		},
    39  		{
    40  			name: "Invalid Skip Rate at Data level",
    41  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
    42  				SkipRate: -10,
    43  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
    44  					ModelVersion: "Version 1",
    45  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
    46  					Values: map[string]float64{
    47  						"*|*|www.website.com": 15.01,
    48  						"*|*|*":               16.01,
    49  					}, Default: 0.01},
    50  				}}},
    51  			Err: errors.New("Invalid SkipRate = '-10' at ext.prebid.floors.data.skiprate"),
    52  		},
    53  		{
    54  			name:     "Invalid FloorMin ",
    55  			floorExt: &openrtb_ext.PriceFloorRules{FloorMin: -10},
    56  			Err:      errors.New("Invalid FloorMin = '-10', value should be >= 0"),
    57  		},
    58  		{
    59  			name: "Invalid FloorSchemaVersion ",
    60  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
    61  				FloorsSchemaVersion: "1",
    62  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
    63  					ModelVersion: "Version 1",
    64  
    65  					Schema: openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}, Delimiter: "|"},
    66  					Values: map[string]float64{
    67  						"banner|300x250|www.website.com": 1.01,
    68  						"banner|300x600|*":               4.01,
    69  					}, Default: 0.01},
    70  				}}},
    71  			Err: errors.New("Invalid FloorsSchemaVersion = '1', supported version 2"),
    72  		},
    73  	}
    74  	for _, tc := range tt {
    75  		t.Run(tc.name, func(t *testing.T) {
    76  			actErr := validateFloorParams(tc.floorExt)
    77  			assert.Equal(t, actErr, tc.Err, tc.name)
    78  		})
    79  	}
    80  }
    81  
    82  func TestSelectValidFloorModelGroups(t *testing.T) {
    83  
    84  	tt := []struct {
    85  		name     string
    86  		floorExt *openrtb_ext.PriceFloorRules
    87  		account  config.Account
    88  		Err      []error
    89  	}{
    90  		{
    91  			name: "Invalid Skip Rate in model Group 1",
    92  			account: config.Account{
    93  				PriceFloors: config.AccountPriceFloors{
    94  					MaxRule:       100,
    95  					MaxSchemaDims: 5,
    96  				},
    97  			},
    98  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
    99  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   100  					ModelWeight:  getIntPtr(50),
   101  					SkipRate:     110,
   102  					ModelVersion: "Version 1",
   103  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   104  					Values: map[string]float64{
   105  						"banner|300x250|www.website.com": 1.01,
   106  						"banner|300x250|*":               2.01,
   107  						"banner|300x600|www.website.com": 3.01,
   108  						"*|728x90|*":                     14.01,
   109  						"*|*|www.website.com":            15.01,
   110  						"*|*|*":                          16.01,
   111  					}, Default: 0.01},
   112  					{
   113  						ModelWeight:  getIntPtr(50),
   114  						SkipRate:     20,
   115  						ModelVersion: "Version 2",
   116  						Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   117  						Values: map[string]float64{
   118  							"banner|300x250|www.website.com": 1.01,
   119  							"banner|300x250|*":               2.01,
   120  							"*|*|www.website.com":            15.01,
   121  							"*|*|*":                          16.01,
   122  						}, Default: 0.01},
   123  				}}},
   124  			Err: []error{errors.New("Invalid Floor Model = 'Version 1' due to SkipRate = '110' is out of range (1-100)")},
   125  		},
   126  		{
   127  			name: "Invalid model weight Model Group 1",
   128  			account: config.Account{
   129  				PriceFloors: config.AccountPriceFloors{
   130  					MaxRule:       100,
   131  					MaxSchemaDims: 5,
   132  				},
   133  			},
   134  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   135  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   136  					ModelWeight:  getIntPtr(-1),
   137  					SkipRate:     10,
   138  					ModelVersion: "Version 1",
   139  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   140  					Values: map[string]float64{
   141  						"banner|300x250|www.website.com": 1.01,
   142  						"banner|300x250|*":               2.01,
   143  						"*|728x90|*":                     14.01,
   144  						"*|*|www.website.com":            15.01,
   145  						"*|*|*":                          16.01,
   146  					}, Default: 0.01},
   147  					{
   148  						ModelWeight:  getIntPtr(50),
   149  						SkipRate:     20,
   150  						ModelVersion: "Version 2",
   151  						Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   152  						Values: map[string]float64{
   153  							"banner|300x250|www.website.com": 1.01,
   154  							"banner|300x250|*":               2.01,
   155  							"*|728x90|*":                     14.01,
   156  							"*|*|www.website.com":            15.01,
   157  							"*|*|*":                          16.01,
   158  						}, Default: 0.01},
   159  				}}},
   160  			Err: []error{errors.New("Invalid Floor Model = 'Version 1' due to ModelWeight = '-1' is out of range (1-100)")},
   161  		},
   162  		{
   163  			name: "Invalid Default Value",
   164  			account: config.Account{
   165  				PriceFloors: config.AccountPriceFloors{
   166  					MaxRule:       100,
   167  					MaxSchemaDims: 5,
   168  				},
   169  			},
   170  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   171  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   172  					ModelWeight:  getIntPtr(50),
   173  					ModelVersion: "Version 1",
   174  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   175  					Values: map[string]float64{
   176  						"banner|300x250|www.website.com": 1.01,
   177  						"*|728x90|*":                     14.01,
   178  						"*|*|www.website.com":            15.01,
   179  						"*|*|*":                          16.01,
   180  					}, Default: -1.0000},
   181  				}}},
   182  			Err: []error{errors.New("Invalid Floor Model = 'Version 1' due to Default = '-1' is less than 0")},
   183  		},
   184  		{
   185  			name: "Invalid Number of Schema dimensions",
   186  			account: config.Account{
   187  				PriceFloors: config.AccountPriceFloors{
   188  					MaxRule:       100,
   189  					MaxSchemaDims: 2,
   190  				},
   191  			},
   192  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   193  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   194  					ModelVersion: "Version 1",
   195  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   196  					Values: map[string]float64{
   197  						"banner|300x250|www.website.com": 1.01,
   198  						"*|728x90|*":                     14.01,
   199  						"*|*|www.website.com":            15.01,
   200  						"*|*|*":                          16.01,
   201  					}},
   202  				}}},
   203  			Err: []error{errors.New("Invalid Floor Model = 'Version 1' due to number of schema fields = '3' are greater than limit 2")},
   204  		},
   205  		{
   206  			name: "Invalid Schema field creativeType",
   207  			account: config.Account{
   208  				PriceFloors: config.AccountPriceFloors{
   209  					MaxRule:       100,
   210  					MaxSchemaDims: 3,
   211  				},
   212  			},
   213  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   214  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   215  					ModelVersion: "Version 1",
   216  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"creativeType", "size", "domain"}},
   217  					Values: map[string]float64{
   218  						"banner|300x250|www.website.com": 1.01,
   219  						"*|728x90|*":                     14.01,
   220  						"*|*|www.website.com":            15.01,
   221  						"*|*|*":                          16.01,
   222  					}},
   223  				}}},
   224  			Err: []error{errors.New("Invalid schema dimension provided = 'creativeType' in Schema Fields = '[creativeType size domain]'")},
   225  		},
   226  		{
   227  			name: "Invalid Number of rules",
   228  			account: config.Account{
   229  				PriceFloors: config.AccountPriceFloors{
   230  					MaxRule:       3,
   231  					MaxSchemaDims: 5,
   232  				},
   233  			},
   234  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   235  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   236  					ModelVersion: "Version 1",
   237  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
   238  					Values: map[string]float64{
   239  						"banner|300x250|www.website.com": 1.01,
   240  						"*|728x90|*":                     14.01,
   241  						"*|*|www.website.com":            15.01,
   242  						"*|*|*":                          16.01,
   243  					}},
   244  				}}},
   245  			Err: []error{errors.New("Invalid Floor Model = 'Version 1' due to number of rules = '4' are greater than limit 3")},
   246  		},
   247  		{
   248  			name: "No Modelgroup present",
   249  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   250  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{}}},
   251  			Err: []error{errors.New("No model group present in floors.data")},
   252  		},
   253  	}
   254  	for _, tc := range tt {
   255  		t.Run(tc.name, func(t *testing.T) {
   256  			_, ErrList := selectValidFloorModelGroups(tc.floorExt.Data.ModelGroups, tc.account)
   257  			assert.Equal(t, ErrList, tc.Err, tc.name)
   258  		})
   259  	}
   260  }
   261  
   262  func TestValidateFloorRulesAndLowerValidRuleKey(t *testing.T) {
   263  
   264  	tt := []struct {
   265  		name         string
   266  		floorExt     *openrtb_ext.PriceFloorRules
   267  		Err          []error
   268  		expctedFloor map[string]float64
   269  	}{
   270  		{
   271  			name: "Invalid floor rule banner|300x600|www.website.com|www.test.com",
   272  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   273  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   274  					ModelVersion: "Version 1",
   275  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}, Delimiter: "|"},
   276  					Values: map[string]float64{
   277  						"BANNER|300x250|WWW.WEBSITE.COM":              1.01,
   278  						"banner|300x250|*":                            2.01,
   279  						"banner|300x600|www.website.com|www.test.com": 3.01,
   280  						"banner|300x600|*":                            4.01,
   281  						"banner|728x90|www.website.com":               5.01,
   282  						"banner|728x90|*":                             6.01,
   283  						"banner|*|www.website.com":                    7.01,
   284  						"banner|*|*":                                  8.01,
   285  						"*|300x250|www.website.com":                   9.01,
   286  						"*|300x250|*":                                 10.01,
   287  						"*|300x600|www.website.com":                   11.01,
   288  						"*|300x600|*":                                 12.01,
   289  						"*|728x90|www.website.com":                    13.01,
   290  						"*|728x90|*":                                  14.01,
   291  						"*|*|www.website.com":                         15.01,
   292  						"*|*|*":                                       16.01,
   293  					}, Default: 0.01},
   294  				}}},
   295  			Err: []error{errors.New("Invalid Floor Rule = 'banner|300x600|www.website.com|www.test.com' for Schema Fields = '[mediaType size domain]'")},
   296  			expctedFloor: map[string]float64{
   297  				"banner|300x250|www.website.com": 1.01,
   298  				"banner|300x250|*":               2.01,
   299  				"banner|300x600|*":               4.01,
   300  				"banner|728x90|www.website.com":  5.01,
   301  				"banner|728x90|*":                6.01,
   302  				"banner|*|www.website.com":       7.01,
   303  				"banner|*|*":                     8.01,
   304  				"*|300x250|www.website.com":      9.01,
   305  				"*|300x250|*":                    10.01,
   306  				"*|300x600|www.website.com":      11.01,
   307  				"*|300x600|*":                    12.01,
   308  				"*|728x90|www.website.com":       13.01,
   309  				"*|728x90|*":                     14.01,
   310  				"*|*|www.website.com":            15.01,
   311  				"*|*|*":                          16.01,
   312  			},
   313  		},
   314  		{
   315  			name: "Invalid floor rule banner|300x600|www.website.com|www.test.com",
   316  			floorExt: &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
   317  				ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
   318  					ModelVersion: "Version 1",
   319  					Schema:       openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}, Delimiter: "|"},
   320  					Values: map[string]float64{
   321  						"banner|300x250|www.website.com": 1.01,
   322  						"banner|300x250|*":               2.01,
   323  						"banner|300x600|www.website.com": 3.01,
   324  						"banner|300x600":                 4.01,
   325  						"banner|728x90|www.website.com":  5.01,
   326  						"banner|728x90|*":                6.01,
   327  						"banner|*|www.website.com":       7.01,
   328  						"banner|*|*":                     8.01,
   329  						"*|300x250|www.website.com":      9.01,
   330  						"*|300x250|*":                    10.01,
   331  						"*|300x600|www.website.com":      11.01,
   332  						"*|300x600|*":                    12.01,
   333  						"*|728x90|www.website.com":       13.01,
   334  						"*|728x90|*":                     14.01,
   335  						"*|*|www.website.com":            15.01,
   336  						"*|*|*":                          16.01,
   337  					}, Default: 0.01},
   338  				}}},
   339  			Err: []error{errors.New("Invalid Floor Rule = 'banner|300x600' for Schema Fields = '[mediaType size domain]'")},
   340  			expctedFloor: map[string]float64{
   341  				"banner|300x250|www.website.com": 1.01,
   342  				"banner|300x250|*":               2.01,
   343  				"banner|300x600|www.website.com": 3.01,
   344  				"banner|728x90|www.website.com":  5.01,
   345  				"banner|728x90|*":                6.01,
   346  				"banner|*|www.website.com":       7.01,
   347  				"banner|*|*":                     8.01,
   348  				"*|300x250|www.website.com":      9.01,
   349  				"*|300x250|*":                    10.01,
   350  				"*|300x600|www.website.com":      11.01,
   351  				"*|300x600|*":                    12.01,
   352  				"*|728x90|www.website.com":       13.01,
   353  				"*|728x90|*":                     14.01,
   354  				"*|*|www.website.com":            15.01,
   355  				"*|*|*":                          16.01,
   356  			},
   357  		},
   358  	}
   359  
   360  	for _, tc := range tt {
   361  		t.Run(tc.name, func(t *testing.T) {
   362  			ErrList := validateFloorRulesAndLowerValidRuleKey(tc.floorExt.Data.ModelGroups[0].Schema, tc.floorExt.Data.ModelGroups[0].Schema.Delimiter, tc.floorExt.Data.ModelGroups[0].Values)
   363  			assert.Equal(t, ErrList, tc.Err, tc.name)
   364  			assert.Equal(t, tc.floorExt.Data.ModelGroups[0].Values, tc.expctedFloor, tc.name)
   365  		})
   366  	}
   367  }
   368  
   369  func TestValidateSchemaDimensions(t *testing.T) {
   370  	tests := []struct {
   371  		name   string
   372  		fields []string
   373  		err    error
   374  	}{
   375  		{
   376  			name:   "valid_fields",
   377  			fields: []string{"deviceType", "size"},
   378  		},
   379  		{
   380  			name:   "invalid_fields",
   381  			fields: []string{"deviceType", "dealType"},
   382  			err:    fmt.Errorf("Invalid schema dimension provided = 'dealType' in Schema Fields = '[deviceType dealType]'"),
   383  		},
   384  	}
   385  	for _, tt := range tests {
   386  		t.Run(tt.name, func(t *testing.T) {
   387  			err := validateSchemaDimensions(tt.fields)
   388  			assert.Equal(t, tt.err, err)
   389  		})
   390  	}
   391  }