github.com/prebid/prebid-server/v2@v2.18.0/config/bidderinfo_test.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  	"testing"
     7  
     8  	"gopkg.in/yaml.v3"
     9  
    10  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  const testInfoFilesPathValid = "./test/bidder-info-valid"
    16  const testSimpleYAML = `
    17  maintainer:
    18    email: some-email@domain.com
    19  gvlVendorID: 42
    20  `
    21  const fullBidderYAMLConfig = `
    22  maintainer:
    23    email: some-email@domain.com
    24  capabilities:
    25    app:
    26      mediaTypes:
    27        - banner
    28        - video
    29        - native
    30    site:
    31      mediaTypes:
    32        - banner
    33        - video
    34        - native
    35    dooh:
    36      mediaTypes:
    37        - banner
    38  modifyingVastXmlAllowed: true
    39  debug:
    40    allow: true
    41  gvlVendorID: 42
    42  experiment:
    43    adsCert:
    44      enabled: true
    45  endpointCompression: GZIP
    46  openrtb:
    47    version: 2.6
    48    gpp-supported: true
    49  endpoint: https://endpoint.com
    50  disabled: false
    51  extra_info: extra-info
    52  app_secret: app-secret
    53  platform_id: 123
    54  userSync:
    55    key: foo
    56    default: iframe
    57    iframe:
    58      url: https://foo.com/sync?mode=iframe&r={{.RedirectURL}}
    59      redirectUrl: https://redirect/setuid/iframe
    60      externalUrl: https://iframe.host
    61      userMacro: UID
    62  xapi:
    63    username: uname
    64    password: pwd
    65    tracker: tracker
    66  `
    67  const testSimpleAliasYAML = `
    68  aliasOf: bidderA
    69  `
    70  
    71  func TestLoadBidderInfoFromDisk(t *testing.T) {
    72  	// should appear in result in mixed case
    73  	bidder := "stroeerCore"
    74  	trueValue := true
    75  
    76  	adapterConfigs := make(map[string]Adapter)
    77  	adapterConfigs[strings.ToLower(bidder)] = Adapter{}
    78  
    79  	infos, err := LoadBidderInfoFromDisk(testInfoFilesPathValid)
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  
    84  	expected := BidderInfos{
    85  		bidder: {
    86  			Disabled: false,
    87  			Maintainer: &MaintainerInfo{
    88  				Email: "some-email@domain.com",
    89  			},
    90  			GVLVendorID: 42,
    91  			Capabilities: &CapabilitiesInfo{
    92  				App: &PlatformInfo{
    93  					MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeNative},
    94  				},
    95  				Site: &PlatformInfo{
    96  					MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
    97  				},
    98  				DOOH: &PlatformInfo{
    99  					MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo},
   100  				},
   101  			},
   102  			Syncer: &Syncer{
   103  				Key: "foo",
   104  				IFrame: &SyncerEndpoint{
   105  					URL:         "https://foo.com/sync?mode=iframe&r={{.RedirectURL}}",
   106  					RedirectURL: "{{.ExternalURL}}/setuid/iframe",
   107  					ExternalURL: "https://iframe.host",
   108  					UserMacro:   "%UID",
   109  				},
   110  				Redirect: &SyncerEndpoint{
   111  					URL:         "https://foo.com/sync?mode=redirect&r={{.RedirectURL}}",
   112  					RedirectURL: "{{.ExternalURL}}/setuid/redirect",
   113  					ExternalURL: "https://redirect.host",
   114  					UserMacro:   "#UID",
   115  				},
   116  				SupportCORS: &trueValue,
   117  			},
   118  		},
   119  	}
   120  	assert.Equal(t, expected, infos)
   121  }
   122  
   123  func TestProcessBidderInfo(t *testing.T) {
   124  	testCases := []struct {
   125  		description         string
   126  		bidderInfos         map[string][]byte
   127  		expectedBidderInfos BidderInfos
   128  		expectError         string
   129  	}{
   130  		{
   131  			description: "Valid bidder info",
   132  			bidderInfos: map[string][]byte{
   133  				"bidderA.yaml": []byte(testSimpleYAML),
   134  			},
   135  			expectedBidderInfos: BidderInfos{
   136  				"bidderA": BidderInfo{
   137  					Maintainer: &MaintainerInfo{
   138  						Email: "some-email@domain.com",
   139  					},
   140  					GVLVendorID: 42,
   141  				},
   142  			},
   143  			expectError: "",
   144  		},
   145  		{
   146  			description: "Bidder doesn't exist in bidder info list",
   147  			bidderInfos: map[string][]byte{
   148  				"unknown.yaml": []byte(testSimpleYAML),
   149  			},
   150  			expectedBidderInfos: nil,
   151  			expectError:         "error parsing config for bidder unknown.yaml",
   152  		},
   153  		{
   154  			description: "Invalid bidder config",
   155  			bidderInfos: map[string][]byte{
   156  				"bidderA.yaml": []byte("invalid bidder config"),
   157  			},
   158  			expectedBidderInfos: nil,
   159  			expectError:         "error parsing config for bidder bidderA.yaml",
   160  		},
   161  		{
   162  			description: "Invalid alias name",
   163  			bidderInfos: map[string][]byte{
   164  				"all.yaml": []byte(testSimpleAliasYAML),
   165  			},
   166  			expectedBidderInfos: nil,
   167  			expectError:         "alias all is a reserved bidder name and cannot be used",
   168  		},
   169  		{
   170  			description: "Valid aliases",
   171  			bidderInfos: map[string][]byte{
   172  				"bidderA.yaml": []byte(fullBidderYAMLConfig),
   173  				"bidderB.yaml": []byte(testSimpleAliasYAML),
   174  			},
   175  			expectedBidderInfos: BidderInfos{
   176  				"bidderA": BidderInfo{
   177  					AppSecret: "app-secret",
   178  					Capabilities: &CapabilitiesInfo{
   179  						App: &PlatformInfo{
   180  							MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
   181  						},
   182  						Site: &PlatformInfo{
   183  							MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
   184  						},
   185  						DOOH: &PlatformInfo{
   186  							MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
   187  						},
   188  					},
   189  					Debug: &DebugInfo{
   190  						Allow: true,
   191  					},
   192  					Disabled:            false,
   193  					Endpoint:            "https://endpoint.com",
   194  					EndpointCompression: "GZIP",
   195  					Experiment: BidderInfoExperiment{
   196  						AdsCert: BidderAdsCert{
   197  							Enabled: true,
   198  						},
   199  					},
   200  					ExtraAdapterInfo: "extra-info",
   201  					GVLVendorID:      42,
   202  					Maintainer: &MaintainerInfo{
   203  						Email: "some-email@domain.com",
   204  					},
   205  					ModifyingVastXmlAllowed: true,
   206  					OpenRTB: &OpenRTBInfo{
   207  						GPPSupported: true,
   208  						Version:      "2.6",
   209  					},
   210  					PlatformID: "123",
   211  					Syncer: &Syncer{
   212  						Key: "foo",
   213  						IFrame: &SyncerEndpoint{
   214  							URL:         "https://foo.com/sync?mode=iframe&r={{.RedirectURL}}",
   215  							RedirectURL: "https://redirect/setuid/iframe",
   216  							ExternalURL: "https://iframe.host",
   217  							UserMacro:   "UID",
   218  						},
   219  					},
   220  					XAPI: AdapterXAPI{
   221  						Username: "uname",
   222  						Password: "pwd",
   223  						Tracker:  "tracker",
   224  					},
   225  				},
   226  				"bidderB": BidderInfo{
   227  					AliasOf:   "bidderA",
   228  					AppSecret: "app-secret",
   229  					Capabilities: &CapabilitiesInfo{
   230  						App: &PlatformInfo{
   231  							MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
   232  						},
   233  						Site: &PlatformInfo{
   234  							MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
   235  						},
   236  						DOOH: &PlatformInfo{
   237  							MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
   238  						},
   239  					},
   240  					Debug: &DebugInfo{
   241  						Allow: true,
   242  					},
   243  					Disabled:            false,
   244  					Endpoint:            "https://endpoint.com",
   245  					EndpointCompression: "GZIP",
   246  					Experiment: BidderInfoExperiment{
   247  						AdsCert: BidderAdsCert{
   248  							Enabled: true,
   249  						},
   250  					},
   251  					ExtraAdapterInfo: "extra-info",
   252  					GVLVendorID:      42,
   253  					Maintainer: &MaintainerInfo{
   254  						Email: "some-email@domain.com",
   255  					},
   256  					ModifyingVastXmlAllowed: true,
   257  					OpenRTB: &OpenRTBInfo{
   258  						GPPSupported: true,
   259  						Version:      "2.6",
   260  					},
   261  					PlatformID: "123",
   262  					Syncer: &Syncer{
   263  						Key: "foo",
   264  					},
   265  					XAPI: AdapterXAPI{
   266  						Username: "uname",
   267  						Password: "pwd",
   268  						Tracker:  "tracker",
   269  					},
   270  				},
   271  			},
   272  		},
   273  	}
   274  
   275  	for _, test := range testCases {
   276  		reader := StubInfoReader{test.bidderInfos}
   277  		bidderInfos, err := processBidderInfos(reader, mockNormalizeBidderName)
   278  		if test.expectError != "" {
   279  			assert.ErrorContains(t, err, test.expectError, "")
   280  		} else {
   281  			assert.Equal(t, test.expectedBidderInfos, bidderInfos, "incorrect bidder infos for test case: %s", test.description)
   282  		}
   283  	}
   284  }
   285  
   286  func TestProcessAliasBidderInfo(t *testing.T) {
   287  	parentWithSyncerKey := BidderInfo{
   288  		AppSecret: "app-secret",
   289  		Capabilities: &CapabilitiesInfo{
   290  			App: &PlatformInfo{
   291  				MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
   292  			},
   293  			Site: &PlatformInfo{
   294  				MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
   295  			},
   296  		},
   297  		Debug: &DebugInfo{
   298  			Allow: true,
   299  		},
   300  		Disabled:            false,
   301  		Endpoint:            "https://endpoint.com",
   302  		EndpointCompression: "GZIP",
   303  		Experiment: BidderInfoExperiment{
   304  			AdsCert: BidderAdsCert{
   305  				Enabled: true,
   306  			},
   307  		},
   308  		ExtraAdapterInfo: "extra-info",
   309  		GVLVendorID:      42,
   310  		Maintainer: &MaintainerInfo{
   311  			Email: "some-email@domain.com",
   312  		},
   313  		ModifyingVastXmlAllowed: true,
   314  		OpenRTB: &OpenRTBInfo{
   315  			GPPSupported: true,
   316  			Version:      "2.6",
   317  		},
   318  		PlatformID: "123",
   319  		Syncer: &Syncer{
   320  			Key: "foo",
   321  			IFrame: &SyncerEndpoint{
   322  				URL:         "https://foo.com/sync?mode=iframe&r={{.RedirectURL}}",
   323  				RedirectURL: "https://redirect/setuid/iframe",
   324  				ExternalURL: "https://iframe.host",
   325  				UserMacro:   "UID",
   326  			},
   327  		},
   328  		XAPI: AdapterXAPI{
   329  			Username: "uname",
   330  			Password: "pwd",
   331  			Tracker:  "tracker",
   332  		},
   333  	}
   334  	aliasBidderInfo := BidderInfo{
   335  		AppSecret: "alias-app-secret",
   336  		Capabilities: &CapabilitiesInfo{
   337  			App: &PlatformInfo{
   338  				MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
   339  			},
   340  			Site: &PlatformInfo{
   341  				MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
   342  			},
   343  		},
   344  		Debug: &DebugInfo{
   345  			Allow: false,
   346  		},
   347  		Disabled:            true,
   348  		Endpoint:            "https://alias-endpoint.com",
   349  		EndpointCompression: "DEFAULT",
   350  		Experiment: BidderInfoExperiment{
   351  			AdsCert: BidderAdsCert{
   352  				Enabled: false,
   353  			},
   354  		},
   355  		ExtraAdapterInfo: "alias-extra-info",
   356  		GVLVendorID:      43,
   357  		Maintainer: &MaintainerInfo{
   358  			Email: "alias-email@domain.com",
   359  		},
   360  		ModifyingVastXmlAllowed: false,
   361  		OpenRTB: &OpenRTBInfo{
   362  			GPPSupported: false,
   363  			Version:      "2.5",
   364  		},
   365  		PlatformID: "456",
   366  		Syncer: &Syncer{
   367  			Key: "alias",
   368  			IFrame: &SyncerEndpoint{
   369  				URL:         "https://alias.com/sync?mode=iframe&r={{.RedirectURL}}",
   370  				RedirectURL: "https://alias-redirect/setuid/iframe",
   371  				ExternalURL: "https://alias-iframe.host",
   372  				UserMacro:   "alias-UID",
   373  			},
   374  		},
   375  		XAPI: AdapterXAPI{
   376  			Username: "alias-uname",
   377  			Password: "alias-pwd",
   378  			Tracker:  "alias-tracker",
   379  		},
   380  	}
   381  	bidderB := parentWithSyncerKey
   382  	bidderB.AliasOf = "bidderA"
   383  	bidderB.Syncer = &Syncer{
   384  		Key: bidderB.Syncer.Key,
   385  	}
   386  
   387  	parentWithoutSyncerKey := BidderInfo{
   388  		Syncer: &Syncer{
   389  			IFrame: &SyncerEndpoint{
   390  				URL:         "https://foo.com/sync?mode=iframe&r={{.RedirectURL}}",
   391  				RedirectURL: "https://redirect/setuid/iframe",
   392  				ExternalURL: "https://iframe.host",
   393  				UserMacro:   "UID",
   394  			},
   395  		},
   396  	}
   397  
   398  	bidderC := parentWithoutSyncerKey
   399  	bidderC.AliasOf = "bidderA"
   400  	bidderC.Syncer = &Syncer{
   401  		Key: "bidderA",
   402  	}
   403  
   404  	testCases := []struct {
   405  		description         string
   406  		aliasInfos          map[string]aliasNillableFields
   407  		bidderInfos         BidderInfos
   408  		expectedBidderInfos BidderInfos
   409  		expectedErr         error
   410  	}{
   411  		{
   412  			description: "inherit all parent info in alias bidder, use parent syncer key as syncer alias key",
   413  			aliasInfos: map[string]aliasNillableFields{
   414  				"bidderB": {
   415  					Disabled:                nil,
   416  					ModifyingVastXmlAllowed: nil,
   417  					Experiment:              nil,
   418  					XAPI:                    nil,
   419  				},
   420  			},
   421  			bidderInfos: BidderInfos{
   422  				"bidderA": parentWithSyncerKey,
   423  				"bidderB": BidderInfo{
   424  					AliasOf: "bidderA",
   425  					// all other fields should be inherited from parent bidder
   426  				},
   427  			},
   428  			expectedErr:         nil,
   429  			expectedBidderInfos: BidderInfos{"bidderA": parentWithSyncerKey, "bidderB": bidderB},
   430  		},
   431  		{
   432  			description: "inherit all parent info in alias bidder, use parent name as syncer alias key",
   433  			aliasInfos: map[string]aliasNillableFields{
   434  				"bidderC": {
   435  					Disabled:                nil,
   436  					ModifyingVastXmlAllowed: nil,
   437  					Experiment:              nil,
   438  					XAPI:                    nil,
   439  				},
   440  			},
   441  			bidderInfos: BidderInfos{
   442  				"bidderA": parentWithoutSyncerKey,
   443  				"bidderC": BidderInfo{
   444  					AliasOf: "bidderA",
   445  					// all other fields should be inherited from parent bidder
   446  				},
   447  			},
   448  			expectedErr:         nil,
   449  			expectedBidderInfos: BidderInfos{"bidderA": parentWithoutSyncerKey, "bidderC": bidderC},
   450  		},
   451  		{
   452  			description: "all bidder info specified for alias, do not inherit from parent bidder",
   453  			aliasInfos: map[string]aliasNillableFields{
   454  				"bidderB": {
   455  					Disabled:                &aliasBidderInfo.Disabled,
   456  					ModifyingVastXmlAllowed: &aliasBidderInfo.ModifyingVastXmlAllowed,
   457  					Experiment:              &aliasBidderInfo.Experiment,
   458  					XAPI:                    &aliasBidderInfo.XAPI,
   459  				},
   460  			},
   461  			bidderInfos: BidderInfos{
   462  				"bidderA": parentWithSyncerKey,
   463  				"bidderB": aliasBidderInfo,
   464  			},
   465  			expectedErr:         nil,
   466  			expectedBidderInfos: BidderInfos{"bidderA": parentWithSyncerKey, "bidderB": aliasBidderInfo},
   467  		},
   468  		{
   469  			description: "invalid alias",
   470  			aliasInfos: map[string]aliasNillableFields{
   471  				"bidderB": {},
   472  			},
   473  			bidderInfos: BidderInfos{
   474  				"bidderB": BidderInfo{
   475  					AliasOf: "bidderA",
   476  				},
   477  			},
   478  			expectedErr: errors.New("bidder: bidderA not found for an alias: bidderB"),
   479  		},
   480  		{
   481  			description: "bidder info not found for an alias",
   482  			aliasInfos: map[string]aliasNillableFields{
   483  				"bidderB": {},
   484  			},
   485  			expectedErr: errors.New("bidder info not found for an alias: bidderB"),
   486  		},
   487  	}
   488  
   489  	for _, test := range testCases {
   490  		bidderInfos, err := processBidderAliases(test.aliasInfos, test.bidderInfos)
   491  		if test.expectedErr != nil {
   492  			assert.Equal(t, test.expectedErr, err)
   493  		} else {
   494  			assert.Equal(t, test.expectedBidderInfos, bidderInfos, test.description)
   495  		}
   496  	}
   497  }
   498  
   499  type StubInfoReader struct {
   500  	mockBidderInfos map[string][]byte
   501  }
   502  
   503  func (r StubInfoReader) Read() (map[string][]byte, error) {
   504  	return r.mockBidderInfos, nil
   505  }
   506  
   507  var testBidderNames = map[string]openrtb_ext.BidderName{
   508  	"biddera": openrtb_ext.BidderName("bidderA"),
   509  	"bidderb": openrtb_ext.BidderName("bidderB"),
   510  	"bidder1": openrtb_ext.BidderName("bidder1"),
   511  	"bidder2": openrtb_ext.BidderName("bidder2"),
   512  	"a":       openrtb_ext.BidderName("a"),
   513  }
   514  
   515  func mockNormalizeBidderName(name string) (openrtb_ext.BidderName, bool) {
   516  	nameLower := strings.ToLower(name)
   517  	bidderName, exists := testBidderNames[nameLower]
   518  	return bidderName, exists
   519  }
   520  
   521  func TestToGVLVendorIDMap(t *testing.T) {
   522  	givenBidderInfos := BidderInfos{
   523  		"bidderA": BidderInfo{Disabled: false, GVLVendorID: 0},
   524  		"bidderB": BidderInfo{Disabled: false, GVLVendorID: 100},
   525  		"bidderC": BidderInfo{Disabled: true, GVLVendorID: 0},
   526  		"bidderD": BidderInfo{Disabled: true, GVLVendorID: 200},
   527  	}
   528  
   529  	expectedGVLVendorIDMap := map[openrtb_ext.BidderName]uint16{
   530  		"bidderB": 100,
   531  	}
   532  
   533  	result := givenBidderInfos.ToGVLVendorIDMap()
   534  	assert.Equal(t, expectedGVLVendorIDMap, result)
   535  }
   536  
   537  const bidderInfoRelativePath = "../static/bidder-info"
   538  
   539  // TestBidderInfoFiles ensures each bidder has a valid static/bidder-info/bidder.yaml file. Validation is performed directly
   540  // against the file system with separate yaml unmarshalling from the LoadBidderInfo func.
   541  func TestBidderInfoFiles(t *testing.T) {
   542  	_, err := LoadBidderInfoFromDisk(bidderInfoRelativePath)
   543  	if err != nil {
   544  		assert.Fail(t, err.Error(), "Errors in bidder info files")
   545  	}
   546  }
   547  
   548  func TestBidderInfoValidationPositive(t *testing.T) {
   549  	bidderInfos := BidderInfos{
   550  		"bidderA": BidderInfo{
   551  			Endpoint:   "http://bidderA.com/openrtb2",
   552  			PlatformID: "A",
   553  			Maintainer: &MaintainerInfo{
   554  				Email: "maintainer@bidderA.com",
   555  			},
   556  			GVLVendorID: 1,
   557  			Capabilities: &CapabilitiesInfo{
   558  				App: &PlatformInfo{
   559  					MediaTypes: []openrtb_ext.BidType{
   560  						openrtb_ext.BidTypeVideo,
   561  						openrtb_ext.BidTypeNative,
   562  						openrtb_ext.BidTypeBanner,
   563  					},
   564  				},
   565  			},
   566  			Syncer: &Syncer{
   567  				Key: "bidderAkey",
   568  				Redirect: &SyncerEndpoint{
   569  					URL:       "http://bidderA.com/usersync",
   570  					UserMacro: "UID",
   571  				},
   572  			},
   573  		},
   574  		"bidderB": BidderInfo{
   575  			Endpoint:   "http://bidderB.com/openrtb2",
   576  			PlatformID: "B",
   577  			Maintainer: &MaintainerInfo{
   578  				Email: "maintainer@bidderB.com",
   579  			},
   580  			GVLVendorID: 2,
   581  			Capabilities: &CapabilitiesInfo{
   582  				Site: &PlatformInfo{
   583  					MediaTypes: []openrtb_ext.BidType{
   584  						openrtb_ext.BidTypeVideo,
   585  						openrtb_ext.BidTypeNative,
   586  						openrtb_ext.BidTypeBanner,
   587  					},
   588  				},
   589  			},
   590  			Syncer: &Syncer{
   591  				Key: "bidderBkey",
   592  				Redirect: &SyncerEndpoint{
   593  					URL:       "http://bidderB.com/usersync",
   594  					UserMacro: "UID",
   595  				},
   596  				FormatOverride: SyncResponseFormatRedirect,
   597  			},
   598  		},
   599  		"bidderC": BidderInfo{
   600  			Endpoint: "http://bidderB.com/openrtb2",
   601  			Maintainer: &MaintainerInfo{
   602  				Email: "maintainer@bidderA.com",
   603  			},
   604  			Capabilities: &CapabilitiesInfo{
   605  				Site: &PlatformInfo{
   606  					MediaTypes: []openrtb_ext.BidType{
   607  						openrtb_ext.BidTypeVideo,
   608  						openrtb_ext.BidTypeNative,
   609  						openrtb_ext.BidTypeBanner,
   610  					},
   611  				},
   612  			},
   613  			AliasOf: "bidderB",
   614  		},
   615  		"bidderD": BidderInfo{
   616  			Endpoint:   "http://bidderD.com/openrtb2",
   617  			PlatformID: "D",
   618  			Maintainer: &MaintainerInfo{
   619  				Email: "maintainer@bidderD.com",
   620  			},
   621  			GVLVendorID: 3,
   622  			Capabilities: &CapabilitiesInfo{
   623  				DOOH: &PlatformInfo{
   624  					MediaTypes: []openrtb_ext.BidType{
   625  						openrtb_ext.BidTypeVideo,
   626  						openrtb_ext.BidTypeNative,
   627  						openrtb_ext.BidTypeBanner,
   628  					},
   629  				},
   630  			},
   631  			Syncer: &Syncer{
   632  				FormatOverride: SyncResponseFormatIFrame,
   633  			},
   634  		},
   635  	}
   636  	errs := bidderInfos.validate(make([]error, 0))
   637  	assert.Len(t, errs, 0, "All bidder infos should be correct")
   638  }
   639  
   640  func TestValidateAliases(t *testing.T) {
   641  	testCase := struct {
   642  		description  string
   643  		bidderInfos  BidderInfos
   644  		expectErrors []error
   645  	}{
   646  		description: "invalid aliases",
   647  		bidderInfos: BidderInfos{
   648  			"bidderA": BidderInfo{
   649  				Endpoint: "http://bidderA.com/openrtb2",
   650  				Maintainer: &MaintainerInfo{
   651  					Email: "maintainer@bidderA.com",
   652  				},
   653  				Capabilities: &CapabilitiesInfo{
   654  					Site: &PlatformInfo{
   655  						MediaTypes: []openrtb_ext.BidType{
   656  							openrtb_ext.BidTypeVideo,
   657  						},
   658  					},
   659  				},
   660  				AliasOf: "bidderB",
   661  			},
   662  			"bidderB": BidderInfo{
   663  				Endpoint: "http://bidderA.com/openrtb2",
   664  				Maintainer: &MaintainerInfo{
   665  					Email: "maintainer@bidderA.com",
   666  				},
   667  				Capabilities: &CapabilitiesInfo{
   668  					Site: &PlatformInfo{
   669  						MediaTypes: []openrtb_ext.BidType{
   670  							openrtb_ext.BidTypeVideo,
   671  						},
   672  					},
   673  				},
   674  				AliasOf: "bidderC",
   675  			},
   676  		},
   677  		expectErrors: []error{
   678  			errors.New("bidder: bidderB cannot be an alias of an alias: bidderA"),
   679  			errors.New("bidder: bidderC not found for an alias: bidderB"),
   680  		},
   681  	}
   682  
   683  	var errs []error
   684  	for bidderName, bidderInfo := range testCase.bidderInfos {
   685  		errs = append(errs, validateAliases(bidderInfo, testCase.bidderInfos, bidderName))
   686  	}
   687  
   688  	assert.ElementsMatch(t, errs, testCase.expectErrors)
   689  }
   690  
   691  func TestBidderInfoValidationNegative(t *testing.T) {
   692  	testCases := []struct {
   693  		description  string
   694  		bidderInfos  BidderInfos
   695  		expectErrors []error
   696  	}{
   697  		{
   698  			"One bidder incorrect url",
   699  			BidderInfos{
   700  				"bidderA": BidderInfo{
   701  					Endpoint: "incorrect",
   702  					Maintainer: &MaintainerInfo{
   703  						Email: "maintainer@bidderA.com",
   704  					},
   705  					Capabilities: &CapabilitiesInfo{
   706  						App: &PlatformInfo{
   707  							MediaTypes: []openrtb_ext.BidType{
   708  								openrtb_ext.BidTypeVideo,
   709  							},
   710  						},
   711  					},
   712  				},
   713  			},
   714  			[]error{
   715  				errors.New("The endpoint: incorrect for bidderA is not a valid URL"),
   716  			},
   717  		},
   718  		{
   719  			"One bidder empty url",
   720  			BidderInfos{
   721  				"bidderA": BidderInfo{
   722  					Endpoint: "",
   723  					Maintainer: &MaintainerInfo{
   724  						Email: "maintainer@bidderA.com",
   725  					},
   726  					Capabilities: &CapabilitiesInfo{
   727  						App: &PlatformInfo{
   728  							MediaTypes: []openrtb_ext.BidType{
   729  								openrtb_ext.BidTypeVideo,
   730  							},
   731  						},
   732  					},
   733  				},
   734  			},
   735  			[]error{
   736  				errors.New("There's no default endpoint available for bidderA. Calls to this bidder/exchange will fail. Please set adapters.bidderA.endpoint in your app config"),
   737  			},
   738  		},
   739  		{
   740  			"One bidder incorrect url template",
   741  			BidderInfos{
   742  				"bidderA": BidderInfo{
   743  					Endpoint: "http://bidderA.com/openrtb2/getuid?{{.incorrect}}",
   744  					Maintainer: &MaintainerInfo{
   745  						Email: "maintainer@bidderA.com",
   746  					},
   747  					Capabilities: &CapabilitiesInfo{
   748  						App: &PlatformInfo{
   749  							MediaTypes: []openrtb_ext.BidType{
   750  								openrtb_ext.BidTypeVideo,
   751  							},
   752  						},
   753  					},
   754  				},
   755  			},
   756  			[]error{
   757  				errors.New("Unable to resolve endpoint: http://bidderA.com/openrtb2/getuid?{{.incorrect}} for adapter: bidderA. template: endpointTemplate:1:37: executing \"endpointTemplate\" at <.incorrect>: can't evaluate field incorrect in type macros.EndpointTemplateParams"),
   758  			},
   759  		},
   760  		{
   761  			"One bidder incorrect url template parameters",
   762  			BidderInfos{
   763  				"bidderA": BidderInfo{
   764  					Endpoint: "http://bidderA.com/openrtb2/getuid?r=[{{.]RedirectURL}}",
   765  					Maintainer: &MaintainerInfo{
   766  						Email: "maintainer@bidderA.com",
   767  					},
   768  					Capabilities: &CapabilitiesInfo{
   769  						App: &PlatformInfo{
   770  							MediaTypes: []openrtb_ext.BidType{
   771  								openrtb_ext.BidTypeVideo,
   772  							},
   773  						},
   774  					},
   775  				},
   776  			},
   777  			[]error{
   778  				errors.New("Invalid endpoint template: http://bidderA.com/openrtb2/getuid?r=[{{.]RedirectURL}} for adapter: bidderA. template: endpointTemplate:1: bad character U+005D ']'"),
   779  			},
   780  		},
   781  		{
   782  			"One bidder no maintainer",
   783  			BidderInfos{
   784  				"bidderA": BidderInfo{
   785  					Endpoint: "http://bidderA.com/openrtb2",
   786  					Capabilities: &CapabilitiesInfo{
   787  						App: &PlatformInfo{
   788  							MediaTypes: []openrtb_ext.BidType{
   789  								openrtb_ext.BidTypeVideo,
   790  							},
   791  						},
   792  					},
   793  				},
   794  			},
   795  			[]error{
   796  				errors.New("missing required field: maintainer.email for adapter: bidderA"),
   797  			},
   798  		},
   799  		{
   800  			"One bidder missing maintainer email",
   801  			BidderInfos{
   802  				"bidderA": BidderInfo{
   803  					Endpoint: "http://bidderA.com/openrtb2",
   804  					Maintainer: &MaintainerInfo{
   805  						Email: "",
   806  					},
   807  					Capabilities: &CapabilitiesInfo{
   808  						App: &PlatformInfo{
   809  							MediaTypes: []openrtb_ext.BidType{
   810  								openrtb_ext.BidTypeVideo,
   811  							},
   812  						},
   813  					},
   814  				},
   815  			},
   816  			[]error{
   817  				errors.New("missing required field: maintainer.email for adapter: bidderA"),
   818  			},
   819  		},
   820  		{
   821  			"One bidder missing capabilities",
   822  			BidderInfos{
   823  				"bidderA": BidderInfo{
   824  					Endpoint: "http://bidderA.com/openrtb2",
   825  					Maintainer: &MaintainerInfo{
   826  						Email: "maintainer@bidderA.com",
   827  					},
   828  				},
   829  			},
   830  			[]error{
   831  				errors.New("missing required field: capabilities for adapter: bidderA"),
   832  			},
   833  		},
   834  		{
   835  			"One bidder missing capabilities site and app and dooh",
   836  			BidderInfos{
   837  				"bidderA": BidderInfo{
   838  					Endpoint: "http://bidderA.com/openrtb2",
   839  					Maintainer: &MaintainerInfo{
   840  						Email: "maintainer@bidderA.com",
   841  					},
   842  					Capabilities: &CapabilitiesInfo{},
   843  				},
   844  			},
   845  			[]error{
   846  				errors.New("at least one of capabilities.site, capabilities.app, or capabilities.dooh must exist for adapter: bidderA"),
   847  			},
   848  		},
   849  		{
   850  			"One bidder incorrect capabilities for app",
   851  			BidderInfos{
   852  				"bidderA": BidderInfo{
   853  					Endpoint: "http://bidderA.com/openrtb2",
   854  					Maintainer: &MaintainerInfo{
   855  						Email: "maintainer@bidderA.com",
   856  					},
   857  					Capabilities: &CapabilitiesInfo{
   858  						App: &PlatformInfo{
   859  							MediaTypes: []openrtb_ext.BidType{
   860  								"incorrect",
   861  							},
   862  						},
   863  					},
   864  				},
   865  			},
   866  			[]error{
   867  				errors.New("capabilities.app failed validation: unrecognized media type at index 0: incorrect for adapter: bidderA"),
   868  			},
   869  		},
   870  		{
   871  			"One bidder incorrect capabilities for dooh",
   872  			BidderInfos{
   873  				"bidderA": BidderInfo{
   874  					Endpoint: "http://bidderA.com/openrtb2",
   875  					Maintainer: &MaintainerInfo{
   876  						Email: "maintainer@bidderA.com",
   877  					},
   878  					Capabilities: &CapabilitiesInfo{
   879  						DOOH: &PlatformInfo{
   880  							MediaTypes: []openrtb_ext.BidType{
   881  								"incorrect",
   882  							},
   883  						},
   884  					},
   885  				},
   886  			},
   887  			[]error{
   888  				errors.New("capabilities.dooh failed validation: unrecognized media type at index 0: incorrect for adapter: bidderA"),
   889  			},
   890  		},
   891  		{
   892  			"One bidder nil capabilities",
   893  			BidderInfos{
   894  				"bidderA": BidderInfo{
   895  					Endpoint: "http://bidderA.com/openrtb2",
   896  					Maintainer: &MaintainerInfo{
   897  						Email: "maintainer@bidderA.com",
   898  					},
   899  					Capabilities: nil,
   900  				},
   901  			},
   902  			[]error{
   903  				errors.New("missing required field: capabilities for adapter: bidderA"),
   904  			},
   905  		},
   906  		{
   907  			"One bidder invalid syncer",
   908  			BidderInfos{
   909  				"bidderA": BidderInfo{
   910  					Endpoint: "http://bidderA.com/openrtb2",
   911  					Maintainer: &MaintainerInfo{
   912  						Email: "maintainer@bidderA.com",
   913  					},
   914  					Capabilities: &CapabilitiesInfo{
   915  						Site: &PlatformInfo{
   916  							MediaTypes: []openrtb_ext.BidType{
   917  								openrtb_ext.BidTypeVideo,
   918  							},
   919  						},
   920  					},
   921  					Syncer: &Syncer{
   922  						Supports: []string{"incorrect"},
   923  					},
   924  				},
   925  			},
   926  			[]error{
   927  				errors.New("syncer could not be created, invalid supported endpoint: incorrect"),
   928  			},
   929  		},
   930  		{
   931  			"Two bidders, one with incorrect url",
   932  			BidderInfos{
   933  				"bidderA": BidderInfo{
   934  					Endpoint: "incorrect",
   935  					Maintainer: &MaintainerInfo{
   936  						Email: "maintainer@bidderA.com",
   937  					},
   938  					Capabilities: &CapabilitiesInfo{
   939  						App: &PlatformInfo{
   940  							MediaTypes: []openrtb_ext.BidType{
   941  								openrtb_ext.BidTypeVideo,
   942  							},
   943  						},
   944  					},
   945  				},
   946  				"bidderB": BidderInfo{
   947  					Endpoint: "http://bidderB.com/openrtb2",
   948  					Maintainer: &MaintainerInfo{
   949  						Email: "maintainer@bidderB.com",
   950  					},
   951  					Capabilities: &CapabilitiesInfo{
   952  						App: &PlatformInfo{
   953  							MediaTypes: []openrtb_ext.BidType{
   954  								openrtb_ext.BidTypeVideo,
   955  							},
   956  						},
   957  					},
   958  				},
   959  			},
   960  			[]error{
   961  				errors.New("The endpoint: incorrect for bidderA is not a valid URL"),
   962  			},
   963  		},
   964  		{
   965  			"Two bidders, both with incorrect url",
   966  			BidderInfos{
   967  				"bidderA": BidderInfo{
   968  					Endpoint: "incorrect",
   969  					Maintainer: &MaintainerInfo{
   970  						Email: "maintainer@bidderA.com",
   971  					},
   972  					Capabilities: &CapabilitiesInfo{
   973  						App: &PlatformInfo{
   974  							MediaTypes: []openrtb_ext.BidType{
   975  								openrtb_ext.BidTypeVideo,
   976  							},
   977  						},
   978  					},
   979  				},
   980  				"bidderB": BidderInfo{
   981  					Endpoint: "incorrect",
   982  					Maintainer: &MaintainerInfo{
   983  						Email: "maintainer@bidderB.com",
   984  					},
   985  					Capabilities: &CapabilitiesInfo{
   986  						App: &PlatformInfo{
   987  							MediaTypes: []openrtb_ext.BidType{
   988  								openrtb_ext.BidTypeVideo,
   989  							},
   990  						},
   991  					},
   992  				},
   993  			},
   994  			[]error{
   995  				errors.New("The endpoint: incorrect for bidderA is not a valid URL"),
   996  				errors.New("The endpoint: incorrect for bidderB is not a valid URL"),
   997  			},
   998  		},
   999  		{
  1000  			"Invalid alias Site capabilities",
  1001  			BidderInfos{
  1002  				"bidderA": BidderInfo{
  1003  					Endpoint: "http://bidderA.com/openrtb2",
  1004  					Maintainer: &MaintainerInfo{
  1005  						Email: "maintainer@bidderA.com",
  1006  					},
  1007  					Capabilities: &CapabilitiesInfo{
  1008  						Site: &PlatformInfo{
  1009  							MediaTypes: []openrtb_ext.BidType{
  1010  								openrtb_ext.BidTypeVideo,
  1011  							},
  1012  						},
  1013  					},
  1014  				},
  1015  				"bidderB": BidderInfo{
  1016  					Endpoint: "http://bidderA.com/openrtb2",
  1017  					Maintainer: &MaintainerInfo{
  1018  						Email: "maintainer@bidderA.com",
  1019  					},
  1020  					Capabilities: &CapabilitiesInfo{
  1021  						App: &PlatformInfo{
  1022  							MediaTypes: []openrtb_ext.BidType{
  1023  								openrtb_ext.BidTypeVideo,
  1024  							},
  1025  						},
  1026  					},
  1027  					AliasOf: "bidderA",
  1028  				},
  1029  			},
  1030  			[]error{
  1031  				errors.New("capabilities for alias: bidderB should be a subset of capabilities for parent bidder: bidderA"),
  1032  			},
  1033  		},
  1034  		{
  1035  			"Invalid alias App capabilities",
  1036  			BidderInfos{
  1037  				"bidderA": BidderInfo{
  1038  					Endpoint: "http://bidderA.com/openrtb2",
  1039  					Maintainer: &MaintainerInfo{
  1040  						Email: "maintainer@bidderA.com",
  1041  					},
  1042  					Capabilities: &CapabilitiesInfo{
  1043  						App: &PlatformInfo{
  1044  							MediaTypes: []openrtb_ext.BidType{
  1045  								openrtb_ext.BidTypeVideo,
  1046  							},
  1047  						},
  1048  					},
  1049  				},
  1050  				"bidderB": BidderInfo{
  1051  					Endpoint: "http://bidderA.com/openrtb2",
  1052  					Maintainer: &MaintainerInfo{
  1053  						Email: "maintainer@bidderA.com",
  1054  					},
  1055  					Capabilities: &CapabilitiesInfo{
  1056  						Site: &PlatformInfo{
  1057  							MediaTypes: []openrtb_ext.BidType{
  1058  								openrtb_ext.BidTypeVideo,
  1059  							},
  1060  						},
  1061  					},
  1062  					AliasOf: "bidderA",
  1063  				},
  1064  			},
  1065  			[]error{
  1066  				errors.New("capabilities for alias: bidderB should be a subset of capabilities for parent bidder: bidderA"),
  1067  			},
  1068  		},
  1069  		{
  1070  			"Invalid alias capabilities",
  1071  			BidderInfos{
  1072  				"bidderA": BidderInfo{
  1073  					Endpoint: "http://bidderA.com/openrtb2",
  1074  					Maintainer: &MaintainerInfo{
  1075  						Email: "maintainer@bidderA.com",
  1076  					},
  1077  					Capabilities: &CapabilitiesInfo{},
  1078  				},
  1079  				"bidderB": BidderInfo{
  1080  					Endpoint: "http://bidderA.com/openrtb2",
  1081  					Maintainer: &MaintainerInfo{
  1082  						Email: "maintainer@bidderA.com",
  1083  					},
  1084  					Capabilities: &CapabilitiesInfo{
  1085  						App: &PlatformInfo{
  1086  							MediaTypes: []openrtb_ext.BidType{
  1087  								openrtb_ext.BidTypeVideo,
  1088  							},
  1089  						},
  1090  					},
  1091  					AliasOf: "bidderA",
  1092  				},
  1093  			},
  1094  			[]error{
  1095  				errors.New("at least one of capabilities.site, capabilities.app, or capabilities.dooh must exist for adapter: bidderA"),
  1096  				errors.New("capabilities for alias: bidderB should be a subset of capabilities for parent bidder: bidderA"),
  1097  			},
  1098  		},
  1099  		{
  1100  			"Invalid alias MediaTypes for site",
  1101  			BidderInfos{
  1102  				"bidderA": BidderInfo{
  1103  					Endpoint: "http://bidderA.com/openrtb2",
  1104  					Maintainer: &MaintainerInfo{
  1105  						Email: "maintainer@bidderA.com",
  1106  					},
  1107  					Capabilities: &CapabilitiesInfo{
  1108  						Site: &PlatformInfo{
  1109  							MediaTypes: []openrtb_ext.BidType{
  1110  								openrtb_ext.BidTypeVideo,
  1111  							},
  1112  						},
  1113  					},
  1114  				},
  1115  				"bidderB": BidderInfo{
  1116  					Endpoint: "http://bidderA.com/openrtb2",
  1117  					Maintainer: &MaintainerInfo{
  1118  						Email: "maintainer@bidderA.com",
  1119  					},
  1120  					Capabilities: &CapabilitiesInfo{
  1121  						Site: &PlatformInfo{
  1122  							MediaTypes: []openrtb_ext.BidType{
  1123  								openrtb_ext.BidTypeBanner,
  1124  								openrtb_ext.BidTypeNative,
  1125  							},
  1126  						},
  1127  					},
  1128  					AliasOf: "bidderA",
  1129  				},
  1130  			},
  1131  			[]error{
  1132  				errors.New("mediaTypes for alias: bidderB should be a subset of MediaTypes for parent bidder: bidderA"),
  1133  			},
  1134  		},
  1135  		{
  1136  			"Invalid alias MediaTypes for app",
  1137  			BidderInfos{
  1138  				"bidderA": BidderInfo{
  1139  					Endpoint: "http://bidderA.com/openrtb2",
  1140  					Maintainer: &MaintainerInfo{
  1141  						Email: "maintainer@bidderA.com",
  1142  					},
  1143  					Capabilities: &CapabilitiesInfo{
  1144  						App: &PlatformInfo{
  1145  							MediaTypes: []openrtb_ext.BidType{
  1146  								openrtb_ext.BidTypeVideo,
  1147  							},
  1148  						},
  1149  					},
  1150  				},
  1151  				"bidderB": BidderInfo{
  1152  					Endpoint: "http://bidderA.com/openrtb2",
  1153  					Maintainer: &MaintainerInfo{
  1154  						Email: "maintainer@bidderA.com",
  1155  					},
  1156  					Capabilities: &CapabilitiesInfo{
  1157  						App: &PlatformInfo{
  1158  							MediaTypes: []openrtb_ext.BidType{
  1159  								openrtb_ext.BidTypeBanner,
  1160  								openrtb_ext.BidTypeNative,
  1161  							},
  1162  						},
  1163  					},
  1164  					AliasOf: "bidderA",
  1165  				},
  1166  			},
  1167  			[]error{
  1168  				errors.New("mediaTypes for alias: bidderB should be a subset of MediaTypes for parent bidder: bidderA"),
  1169  			},
  1170  		},
  1171  		{
  1172  			"Invalid parent bidder capabilities",
  1173  			BidderInfos{
  1174  				"bidderA": BidderInfo{
  1175  					Endpoint: "http://bidderA.com/openrtb2",
  1176  					Maintainer: &MaintainerInfo{
  1177  						Email: "maintainer@bidderA.com",
  1178  					},
  1179  				},
  1180  				"bidderB": BidderInfo{
  1181  					Endpoint: "http://bidderA.com/openrtb2",
  1182  					Maintainer: &MaintainerInfo{
  1183  						Email: "maintainer@bidderA.com",
  1184  					},
  1185  					Capabilities: &CapabilitiesInfo{
  1186  						App: &PlatformInfo{
  1187  							MediaTypes: []openrtb_ext.BidType{
  1188  								openrtb_ext.BidTypeBanner,
  1189  							},
  1190  						},
  1191  					},
  1192  					AliasOf: "bidderA",
  1193  				},
  1194  			},
  1195  			[]error{
  1196  				errors.New("missing required field: capabilities for adapter: bidderA"),
  1197  				errors.New("capabilities for alias: bidderB should be a subset of capabilities for parent bidder: bidderA"),
  1198  			},
  1199  		},
  1200  		{
  1201  			"Invalid site alias capabilities with both site and app",
  1202  			BidderInfos{
  1203  				"bidderA": BidderInfo{
  1204  					Endpoint: "http://bidderA.com/openrtb2",
  1205  					Maintainer: &MaintainerInfo{
  1206  						Email: "maintainer@bidderA.com",
  1207  					},
  1208  					Capabilities: &CapabilitiesInfo{
  1209  						App: &PlatformInfo{
  1210  							MediaTypes: []openrtb_ext.BidType{
  1211  								openrtb_ext.BidTypeBanner,
  1212  								openrtb_ext.BidTypeNative,
  1213  							},
  1214  						},
  1215  						Site: &PlatformInfo{
  1216  							MediaTypes: []openrtb_ext.BidType{
  1217  								openrtb_ext.BidTypeNative,
  1218  							},
  1219  						},
  1220  					},
  1221  				},
  1222  				"bidderB": BidderInfo{
  1223  					Endpoint: "http://bidderA.com/openrtb2",
  1224  					Maintainer: &MaintainerInfo{
  1225  						Email: "maintainer@bidderA.com",
  1226  					},
  1227  					Capabilities: &CapabilitiesInfo{
  1228  						App: &PlatformInfo{
  1229  							MediaTypes: []openrtb_ext.BidType{
  1230  								openrtb_ext.BidTypeBanner,
  1231  								openrtb_ext.BidTypeNative,
  1232  							},
  1233  						},
  1234  						Site: &PlatformInfo{
  1235  							MediaTypes: []openrtb_ext.BidType{
  1236  								openrtb_ext.BidTypeBanner,
  1237  								openrtb_ext.BidTypeNative,
  1238  							},
  1239  						},
  1240  					},
  1241  					AliasOf: "bidderA",
  1242  				},
  1243  			},
  1244  			[]error{
  1245  				errors.New("mediaTypes for alias: bidderB should be a subset of MediaTypes for parent bidder: bidderA"),
  1246  			},
  1247  		},
  1248  		{
  1249  			"Invalid app alias capabilities with both site and app",
  1250  			BidderInfos{
  1251  				"bidderA": BidderInfo{
  1252  					Endpoint: "http://bidderA.com/openrtb2",
  1253  					Maintainer: &MaintainerInfo{
  1254  						Email: "maintainer@bidderA.com",
  1255  					},
  1256  					Capabilities: &CapabilitiesInfo{
  1257  						App: &PlatformInfo{
  1258  							MediaTypes: []openrtb_ext.BidType{
  1259  								openrtb_ext.BidTypeBanner,
  1260  								openrtb_ext.BidTypeNative,
  1261  							},
  1262  						},
  1263  						Site: &PlatformInfo{
  1264  							MediaTypes: []openrtb_ext.BidType{
  1265  								openrtb_ext.BidTypeNative,
  1266  							},
  1267  						},
  1268  					},
  1269  				},
  1270  				"bidderB": BidderInfo{
  1271  					Endpoint: "http://bidderA.com/openrtb2",
  1272  					Maintainer: &MaintainerInfo{
  1273  						Email: "maintainer@bidderA.com",
  1274  					},
  1275  					Capabilities: &CapabilitiesInfo{
  1276  						App: &PlatformInfo{
  1277  							MediaTypes: []openrtb_ext.BidType{
  1278  								openrtb_ext.BidTypeBanner,
  1279  								openrtb_ext.BidTypeNative,
  1280  							},
  1281  						},
  1282  						Site: &PlatformInfo{
  1283  							MediaTypes: []openrtb_ext.BidType{
  1284  								openrtb_ext.BidTypeBanner,
  1285  								openrtb_ext.BidTypeNative,
  1286  							},
  1287  						},
  1288  					},
  1289  					AliasOf: "bidderA",
  1290  				},
  1291  			},
  1292  			[]error{
  1293  				errors.New("mediaTypes for alias: bidderB should be a subset of MediaTypes for parent bidder: bidderA"),
  1294  			},
  1295  		},
  1296  		{
  1297  			"Invalid parent bidder for alias",
  1298  			BidderInfos{
  1299  				"bidderB": BidderInfo{
  1300  					Endpoint: "http://bidderA.com/openrtb2",
  1301  					Maintainer: &MaintainerInfo{
  1302  						Email: "maintainer@bidderA.com",
  1303  					},
  1304  					Capabilities: &CapabilitiesInfo{
  1305  						App: &PlatformInfo{
  1306  							MediaTypes: []openrtb_ext.BidType{
  1307  								openrtb_ext.BidTypeBanner,
  1308  								openrtb_ext.BidTypeNative,
  1309  							},
  1310  						},
  1311  						Site: &PlatformInfo{
  1312  							MediaTypes: []openrtb_ext.BidType{
  1313  								openrtb_ext.BidTypeBanner,
  1314  								openrtb_ext.BidTypeNative,
  1315  							},
  1316  						},
  1317  					},
  1318  					AliasOf: "bidderC",
  1319  				},
  1320  			},
  1321  			[]error{
  1322  				errors.New("parent bidder: bidderC not found for an alias: bidderB"),
  1323  			},
  1324  		},
  1325  		{
  1326  			"Invalid format override value",
  1327  			BidderInfos{
  1328  				"bidderB": BidderInfo{
  1329  					Endpoint: "http://bidderA.com/openrtb2",
  1330  					Maintainer: &MaintainerInfo{
  1331  						Email: "maintainer@bidderA.com",
  1332  					},
  1333  					Capabilities: &CapabilitiesInfo{
  1334  						App: &PlatformInfo{
  1335  							MediaTypes: []openrtb_ext.BidType{
  1336  								openrtb_ext.BidTypeBanner,
  1337  								openrtb_ext.BidTypeNative,
  1338  							},
  1339  						},
  1340  						Site: &PlatformInfo{
  1341  							MediaTypes: []openrtb_ext.BidType{
  1342  								openrtb_ext.BidTypeBanner,
  1343  								openrtb_ext.BidTypeNative,
  1344  							},
  1345  						},
  1346  					},
  1347  					Syncer: &Syncer{
  1348  						FormatOverride: "x",
  1349  					},
  1350  				},
  1351  			},
  1352  			[]error{
  1353  				errors.New("syncer could not be created, invalid format override value: x"),
  1354  			},
  1355  		},
  1356  	}
  1357  
  1358  	for _, test := range testCases {
  1359  		errs := test.bidderInfos.validate(make([]error, 0))
  1360  		assert.ElementsMatch(t, errs, test.expectErrors, "incorrect errors returned for test: %s", test.description)
  1361  	}
  1362  }
  1363  
  1364  func TestSyncerOverride(t *testing.T) {
  1365  	var (
  1366  		trueValue  = true
  1367  		falseValue = false
  1368  	)
  1369  
  1370  	testCases := []struct {
  1371  		description   string
  1372  		givenOriginal *Syncer
  1373  		givenOverride *Syncer
  1374  		expected      *Syncer
  1375  	}{
  1376  		{
  1377  			description:   "Nil",
  1378  			givenOriginal: nil,
  1379  			givenOverride: nil,
  1380  			expected:      nil,
  1381  		},
  1382  		{
  1383  			description:   "Original Nil",
  1384  			givenOriginal: nil,
  1385  			givenOverride: &Syncer{Key: "anyKey"},
  1386  			expected:      &Syncer{Key: "anyKey"},
  1387  		},
  1388  		{
  1389  			description:   "Original Empty",
  1390  			givenOriginal: &Syncer{},
  1391  			givenOverride: &Syncer{Key: "anyKey"},
  1392  			expected:      &Syncer{Key: "anyKey"},
  1393  		},
  1394  		{
  1395  			description:   "Override Nil",
  1396  			givenOriginal: &Syncer{Key: "anyKey"},
  1397  			givenOverride: nil,
  1398  			expected:      &Syncer{Key: "anyKey"},
  1399  		},
  1400  		{
  1401  			description:   "Override Empty",
  1402  			givenOriginal: &Syncer{Key: "anyKey"},
  1403  			givenOverride: &Syncer{},
  1404  			expected:      &Syncer{Key: "anyKey"},
  1405  		},
  1406  		{
  1407  			description:   "Override Key",
  1408  			givenOriginal: &Syncer{Key: "original"},
  1409  			givenOverride: &Syncer{Key: "override"},
  1410  			expected:      &Syncer{Key: "override"},
  1411  		},
  1412  		{
  1413  			description:   "Override IFrame",
  1414  			givenOriginal: &Syncer{IFrame: &SyncerEndpoint{URL: "original"}},
  1415  			givenOverride: &Syncer{IFrame: &SyncerEndpoint{URL: "override"}},
  1416  			expected:      &Syncer{IFrame: &SyncerEndpoint{URL: "override"}},
  1417  		},
  1418  		{
  1419  			description:   "Override Redirect",
  1420  			givenOriginal: &Syncer{Redirect: &SyncerEndpoint{URL: "original"}},
  1421  			givenOverride: &Syncer{Redirect: &SyncerEndpoint{URL: "override"}},
  1422  			expected:      &Syncer{Redirect: &SyncerEndpoint{URL: "override"}},
  1423  		},
  1424  		{
  1425  			description:   "Override ExternalURL",
  1426  			givenOriginal: &Syncer{ExternalURL: "original"},
  1427  			givenOverride: &Syncer{ExternalURL: "override"},
  1428  			expected:      &Syncer{ExternalURL: "override"},
  1429  		},
  1430  		{
  1431  			description:   "Override SupportCORS",
  1432  			givenOriginal: &Syncer{SupportCORS: &trueValue},
  1433  			givenOverride: &Syncer{SupportCORS: &falseValue},
  1434  			expected:      &Syncer{SupportCORS: &falseValue},
  1435  		},
  1436  		{
  1437  			description:   "Override Partial - Other Fields Untouched",
  1438  			givenOriginal: &Syncer{Key: "originalKey", ExternalURL: "originalExternalURL"},
  1439  			givenOverride: &Syncer{ExternalURL: "overrideExternalURL"},
  1440  			expected:      &Syncer{Key: "originalKey", ExternalURL: "overrideExternalURL"},
  1441  		},
  1442  	}
  1443  
  1444  	for _, test := range testCases {
  1445  		result := test.givenOverride.Override(test.givenOriginal)
  1446  		assert.Equal(t, test.expected, result, test.description)
  1447  	}
  1448  }
  1449  
  1450  func TestSyncerEndpointOverride(t *testing.T) {
  1451  	testCases := []struct {
  1452  		description   string
  1453  		givenOriginal *SyncerEndpoint
  1454  		givenOverride *SyncerEndpoint
  1455  		expected      *SyncerEndpoint
  1456  	}{
  1457  		{
  1458  			description:   "Nil",
  1459  			givenOriginal: nil,
  1460  			givenOverride: nil,
  1461  			expected:      nil,
  1462  		},
  1463  		{
  1464  			description:   "Original Nil",
  1465  			givenOriginal: nil,
  1466  			givenOverride: &SyncerEndpoint{URL: "anyURL"},
  1467  			expected:      &SyncerEndpoint{URL: "anyURL"},
  1468  		},
  1469  		{
  1470  			description:   "Original Empty",
  1471  			givenOriginal: &SyncerEndpoint{},
  1472  			givenOverride: &SyncerEndpoint{URL: "anyURL"},
  1473  			expected:      &SyncerEndpoint{URL: "anyURL"},
  1474  		},
  1475  		{
  1476  			description:   "Override Nil",
  1477  			givenOriginal: &SyncerEndpoint{URL: "anyURL"},
  1478  			givenOverride: nil,
  1479  			expected:      &SyncerEndpoint{URL: "anyURL"},
  1480  		},
  1481  		{
  1482  			description:   "Override Empty",
  1483  			givenOriginal: &SyncerEndpoint{URL: "anyURL"},
  1484  			givenOverride: &SyncerEndpoint{},
  1485  			expected:      &SyncerEndpoint{URL: "anyURL"},
  1486  		},
  1487  		{
  1488  			description:   "Override URL",
  1489  			givenOriginal: &SyncerEndpoint{URL: "original"},
  1490  			givenOverride: &SyncerEndpoint{URL: "override"},
  1491  			expected:      &SyncerEndpoint{URL: "override"},
  1492  		},
  1493  		{
  1494  			description:   "Override RedirectURL",
  1495  			givenOriginal: &SyncerEndpoint{RedirectURL: "original"},
  1496  			givenOverride: &SyncerEndpoint{RedirectURL: "override"},
  1497  			expected:      &SyncerEndpoint{RedirectURL: "override"},
  1498  		},
  1499  		{
  1500  			description:   "Override ExternalURL",
  1501  			givenOriginal: &SyncerEndpoint{ExternalURL: "original"},
  1502  			givenOverride: &SyncerEndpoint{ExternalURL: "override"},
  1503  			expected:      &SyncerEndpoint{ExternalURL: "override"},
  1504  		},
  1505  		{
  1506  			description:   "Override UserMacro",
  1507  			givenOriginal: &SyncerEndpoint{UserMacro: "original"},
  1508  			givenOverride: &SyncerEndpoint{UserMacro: "override"},
  1509  			expected:      &SyncerEndpoint{UserMacro: "override"},
  1510  		},
  1511  		{
  1512  			description:   "Override",
  1513  			givenOriginal: &SyncerEndpoint{URL: "originalURL", RedirectURL: "originalRedirectURL", ExternalURL: "originalExternalURL", UserMacro: "originalUserMacro"},
  1514  			givenOverride: &SyncerEndpoint{URL: "overideURL", RedirectURL: "overideRedirectURL", ExternalURL: "overideExternalURL", UserMacro: "overideUserMacro"},
  1515  			expected:      &SyncerEndpoint{URL: "overideURL", RedirectURL: "overideRedirectURL", ExternalURL: "overideExternalURL", UserMacro: "overideUserMacro"},
  1516  		},
  1517  	}
  1518  
  1519  	for _, test := range testCases {
  1520  		result := test.givenOverride.Override(test.givenOriginal)
  1521  		assert.Equal(t, test.expected, result, test.description)
  1522  	}
  1523  }
  1524  
  1525  func TestApplyBidderInfoConfigSyncerOverrides(t *testing.T) {
  1526  	var (
  1527  		givenFileSystem = BidderInfos{"a": {Syncer: &Syncer{Key: "original"}}}
  1528  		givenConfig     = nillableFieldBidderInfos{
  1529  			"a": {
  1530  				bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}},
  1531  			},
  1532  		}
  1533  		expected = BidderInfos{"a": {Syncer: &Syncer{Key: "override"}}}
  1534  	)
  1535  
  1536  	result, resultErr := applyBidderInfoConfigOverrides(givenConfig, givenFileSystem, mockNormalizeBidderName)
  1537  	assert.NoError(t, resultErr)
  1538  	assert.Equal(t, expected, result)
  1539  }
  1540  
  1541  func TestApplyBidderInfoConfigOverrides(t *testing.T) {
  1542  	falseValue := false
  1543  
  1544  	var testCases = []struct {
  1545  		description            string
  1546  		givenFsBidderInfos     BidderInfos
  1547  		givenConfigBidderInfos nillableFieldBidderInfos
  1548  		expectedError          string
  1549  		expectedBidderInfos    BidderInfos
  1550  	}{
  1551  		{
  1552  			description:            "Don't override endpoint",
  1553  			givenFsBidderInfos:     BidderInfos{"a": {Endpoint: "original"}},
  1554  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1555  			expectedBidderInfos:    BidderInfos{"a": {Endpoint: "original", Syncer: &Syncer{Key: "override"}}},
  1556  		},
  1557  		{
  1558  			description:            "Override endpoint",
  1559  			givenFsBidderInfos:     BidderInfos{"a": {Endpoint: "original"}},
  1560  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Endpoint: "override", Syncer: &Syncer{Key: "override"}}}},
  1561  			expectedBidderInfos:    BidderInfos{"a": {Endpoint: "override", Syncer: &Syncer{Key: "override"}}},
  1562  		},
  1563  		{
  1564  			description:            "Don't override ExtraAdapterInfo",
  1565  			givenFsBidderInfos:     BidderInfos{"a": {ExtraAdapterInfo: "original"}},
  1566  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1567  			expectedBidderInfos:    BidderInfos{"a": {ExtraAdapterInfo: "original", Syncer: &Syncer{Key: "override"}}},
  1568  		},
  1569  		{
  1570  			description:            "Override ExtraAdapterInfo",
  1571  			givenFsBidderInfos:     BidderInfos{"a": {ExtraAdapterInfo: "original"}},
  1572  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{ExtraAdapterInfo: "override", Syncer: &Syncer{Key: "override"}}}},
  1573  			expectedBidderInfos:    BidderInfos{"a": {ExtraAdapterInfo: "override", Syncer: &Syncer{Key: "override"}}},
  1574  		},
  1575  		{
  1576  			description:            "Don't override Maintainer",
  1577  			givenFsBidderInfos:     BidderInfos{"a": {Maintainer: &MaintainerInfo{Email: "original"}}},
  1578  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1579  			expectedBidderInfos:    BidderInfos{"a": {Maintainer: &MaintainerInfo{Email: "original"}, Syncer: &Syncer{Key: "override"}}},
  1580  		},
  1581  		{
  1582  			description:            "Override maintainer",
  1583  			givenFsBidderInfos:     BidderInfos{"a": {Maintainer: &MaintainerInfo{Email: "original"}}},
  1584  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Maintainer: &MaintainerInfo{Email: "override"}, Syncer: &Syncer{Key: "override"}}}},
  1585  			expectedBidderInfos:    BidderInfos{"a": {Maintainer: &MaintainerInfo{Email: "override"}, Syncer: &Syncer{Key: "override"}}},
  1586  		},
  1587  		{
  1588  			description: "Don't override Capabilities",
  1589  			givenFsBidderInfos: BidderInfos{"a": {
  1590  				Capabilities: &CapabilitiesInfo{App: &PlatformInfo{MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeVideo}}},
  1591  			}},
  1592  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1593  			expectedBidderInfos: BidderInfos{"a": {
  1594  				Syncer:       &Syncer{Key: "override"},
  1595  				Capabilities: &CapabilitiesInfo{App: &PlatformInfo{MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeVideo}}},
  1596  			}},
  1597  		},
  1598  		{
  1599  			description: "Override Capabilities",
  1600  			givenFsBidderInfos: BidderInfos{"a": {
  1601  				Capabilities: &CapabilitiesInfo{App: &PlatformInfo{MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeVideo}}},
  1602  			}},
  1603  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{
  1604  				Syncer:       &Syncer{Key: "override"},
  1605  				Capabilities: &CapabilitiesInfo{App: &PlatformInfo{MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner}}},
  1606  			}}},
  1607  			expectedBidderInfos: BidderInfos{"a": {
  1608  				Syncer:       &Syncer{Key: "override"},
  1609  				Capabilities: &CapabilitiesInfo{App: &PlatformInfo{MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner}}},
  1610  			}},
  1611  		},
  1612  		{
  1613  			description:            "Don't override Debug",
  1614  			givenFsBidderInfos:     BidderInfos{"a": {Debug: &DebugInfo{Allow: true}}},
  1615  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1616  			expectedBidderInfos:    BidderInfos{"a": {Debug: &DebugInfo{Allow: true}, Syncer: &Syncer{Key: "override"}}},
  1617  		},
  1618  		{
  1619  			description:            "Override Debug",
  1620  			givenFsBidderInfos:     BidderInfos{"a": {Debug: &DebugInfo{Allow: true}}},
  1621  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Debug: &DebugInfo{Allow: false}, Syncer: &Syncer{Key: "override"}}}},
  1622  			expectedBidderInfos:    BidderInfos{"a": {Debug: &DebugInfo{Allow: false}, Syncer: &Syncer{Key: "override"}}},
  1623  		},
  1624  		{
  1625  			description:            "Don't override GVLVendorID",
  1626  			givenFsBidderInfos:     BidderInfos{"a": {GVLVendorID: 5}},
  1627  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1628  			expectedBidderInfos:    BidderInfos{"a": {GVLVendorID: 5, Syncer: &Syncer{Key: "override"}}},
  1629  		},
  1630  		{
  1631  			description:            "Override GVLVendorID",
  1632  			givenFsBidderInfos:     BidderInfos{"a": {}},
  1633  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{GVLVendorID: 5, Syncer: &Syncer{Key: "override"}}}},
  1634  			expectedBidderInfos:    BidderInfos{"a": {GVLVendorID: 5, Syncer: &Syncer{Key: "override"}}},
  1635  		},
  1636  		{
  1637  			description: "Don't override XAPI",
  1638  			givenFsBidderInfos: BidderInfos{"a": {
  1639  				XAPI: AdapterXAPI{Username: "username1", Password: "password2", Tracker: "tracker3"},
  1640  			}},
  1641  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1642  			expectedBidderInfos: BidderInfos{"a": {
  1643  				XAPI:   AdapterXAPI{Username: "username1", Password: "password2", Tracker: "tracker3"},
  1644  				Syncer: &Syncer{Key: "override"}}},
  1645  		},
  1646  		{
  1647  			description: "Override XAPI",
  1648  			givenFsBidderInfos: BidderInfos{"a": {
  1649  				XAPI: AdapterXAPI{Username: "username", Password: "password", Tracker: "tracker"}}},
  1650  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{
  1651  				XAPI:   AdapterXAPI{Username: "username1", Password: "password2", Tracker: "tracker3"},
  1652  				Syncer: &Syncer{Key: "override"}}}},
  1653  			expectedBidderInfos: BidderInfos{"a": {
  1654  				XAPI:   AdapterXAPI{Username: "username1", Password: "password2", Tracker: "tracker3"},
  1655  				Syncer: &Syncer{Key: "override"}}},
  1656  		},
  1657  		{
  1658  			description:            "Don't override PlatformID",
  1659  			givenFsBidderInfos:     BidderInfos{"a": {PlatformID: "PlatformID"}},
  1660  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1661  			expectedBidderInfos:    BidderInfos{"a": {PlatformID: "PlatformID", Syncer: &Syncer{Key: "override"}}},
  1662  		},
  1663  		{
  1664  			description:            "Override PlatformID",
  1665  			givenFsBidderInfos:     BidderInfos{"a": {PlatformID: "PlatformID1"}},
  1666  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{PlatformID: "PlatformID2", Syncer: &Syncer{Key: "override"}}}},
  1667  			expectedBidderInfos:    BidderInfos{"a": {PlatformID: "PlatformID2", Syncer: &Syncer{Key: "override"}}},
  1668  		},
  1669  		{
  1670  			description:            "Don't override AppSecret",
  1671  			givenFsBidderInfos:     BidderInfos{"a": {AppSecret: "AppSecret"}},
  1672  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1673  			expectedBidderInfos:    BidderInfos{"a": {AppSecret: "AppSecret", Syncer: &Syncer{Key: "override"}}},
  1674  		},
  1675  		{
  1676  			description:            "Override AppSecret",
  1677  			givenFsBidderInfos:     BidderInfos{"a": {AppSecret: "AppSecret1"}},
  1678  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{AppSecret: "AppSecret2", Syncer: &Syncer{Key: "override"}}}},
  1679  			expectedBidderInfos:    BidderInfos{"a": {AppSecret: "AppSecret2", Syncer: &Syncer{Key: "override"}}},
  1680  		},
  1681  		{
  1682  			description:            "Don't override EndpointCompression",
  1683  			givenFsBidderInfos:     BidderInfos{"a": {EndpointCompression: "GZIP"}},
  1684  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1685  			expectedBidderInfos:    BidderInfos{"a": {EndpointCompression: "GZIP", Syncer: &Syncer{Key: "override"}}},
  1686  		},
  1687  		{
  1688  			description:            "Override EndpointCompression",
  1689  			givenFsBidderInfos:     BidderInfos{"a": {EndpointCompression: "GZIP"}},
  1690  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{EndpointCompression: "LZ77", Syncer: &Syncer{Key: "override"}}}},
  1691  			expectedBidderInfos:    BidderInfos{"a": {EndpointCompression: "LZ77", Syncer: &Syncer{Key: "override"}}},
  1692  		},
  1693  		{
  1694  			description:            "Don't override Disabled",
  1695  			givenFsBidderInfos:     BidderInfos{"a": {Disabled: true}},
  1696  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Disabled: false, Syncer: &Syncer{Key: "override"}}, nillableFields: bidderInfoNillableFields{Disabled: nil}}},
  1697  			expectedBidderInfos:    BidderInfos{"a": {Disabled: true, Syncer: &Syncer{Key: "override"}}},
  1698  		},
  1699  		{
  1700  			description:            "Override Disabled",
  1701  			givenFsBidderInfos:     BidderInfos{"a": {Disabled: true}},
  1702  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Disabled: false, Syncer: &Syncer{Key: "override"}}, nillableFields: bidderInfoNillableFields{Disabled: &falseValue}}},
  1703  			expectedBidderInfos:    BidderInfos{"a": {Disabled: false, Syncer: &Syncer{Key: "override"}}},
  1704  		},
  1705  		{
  1706  			description:            "Don't override ModifyingVastXmlAllowed",
  1707  			givenFsBidderInfos:     BidderInfos{"a": {ModifyingVastXmlAllowed: true}},
  1708  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{ModifyingVastXmlAllowed: false, Syncer: &Syncer{Key: "override"}}, nillableFields: bidderInfoNillableFields{ModifyingVastXmlAllowed: nil}}},
  1709  			expectedBidderInfos:    BidderInfos{"a": {ModifyingVastXmlAllowed: true, Syncer: &Syncer{Key: "override"}}},
  1710  		},
  1711  		{
  1712  			description:            "Override ModifyingVastXmlAllowed",
  1713  			givenFsBidderInfos:     BidderInfos{"a": {ModifyingVastXmlAllowed: true}},
  1714  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{ModifyingVastXmlAllowed: false, Syncer: &Syncer{Key: "override"}}, nillableFields: bidderInfoNillableFields{ModifyingVastXmlAllowed: &falseValue}}},
  1715  			expectedBidderInfos:    BidderInfos{"a": {ModifyingVastXmlAllowed: false, Syncer: &Syncer{Key: "override"}}},
  1716  		},
  1717  		{
  1718  			description:            "Don't override OpenRTB",
  1719  			givenFsBidderInfos:     BidderInfos{"a": {OpenRTB: &OpenRTBInfo{Version: "1"}}},
  1720  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}}}},
  1721  			expectedBidderInfos:    BidderInfos{"a": {OpenRTB: &OpenRTBInfo{Version: "1"}, Syncer: &Syncer{Key: "override"}}},
  1722  		},
  1723  		{
  1724  			description:            "Override OpenRTB",
  1725  			givenFsBidderInfos:     BidderInfos{"a": {OpenRTB: &OpenRTBInfo{Version: "1"}}},
  1726  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{OpenRTB: &OpenRTBInfo{Version: "2"}, Syncer: &Syncer{Key: "override"}}}},
  1727  			expectedBidderInfos:    BidderInfos{"a": {OpenRTB: &OpenRTBInfo{Version: "2"}, Syncer: &Syncer{Key: "override"}}},
  1728  		},
  1729  		{
  1730  			description:            "Don't override AliasOf",
  1731  			givenFsBidderInfos:     BidderInfos{"a": {AliasOf: "Alias1"}},
  1732  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{}}},
  1733  			expectedBidderInfos:    BidderInfos{"a": {AliasOf: "Alias1"}},
  1734  		},
  1735  		{
  1736  			description:            "Attempt override AliasOf but ignored",
  1737  			givenFsBidderInfos:     BidderInfos{"a": {AliasOf: "Alias1"}},
  1738  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{AliasOf: "Alias2"}}},
  1739  			expectedBidderInfos:    BidderInfos{"a": {AliasOf: "Alias1"}},
  1740  		},
  1741  		{
  1742  			description:            "Two bidder infos: One with overrides and one without",
  1743  			givenFsBidderInfos:     BidderInfos{"a": {Endpoint: "original"}, "b": {Endpoint: "b endpoint"}},
  1744  			givenConfigBidderInfos: nillableFieldBidderInfos{"a": {bidderInfo: BidderInfo{Endpoint: "override", Syncer: &Syncer{Key: "override"}}}},
  1745  			expectedBidderInfos:    BidderInfos{"a": {Endpoint: "override", Syncer: &Syncer{Key: "override"}}, "b": {Endpoint: "b endpoint"}},
  1746  		},
  1747  	}
  1748  	for _, test := range testCases {
  1749  		bidderInfos, resultErr := applyBidderInfoConfigOverrides(test.givenConfigBidderInfos, test.givenFsBidderInfos, mockNormalizeBidderName)
  1750  		assert.NoError(t, resultErr, test.description+":err")
  1751  		assert.Equal(t, test.expectedBidderInfos, bidderInfos, test.description+":result")
  1752  	}
  1753  }
  1754  
  1755  func TestApplyBidderInfoConfigOverridesInvalid(t *testing.T) {
  1756  	var testCases = []struct {
  1757  		description                   string
  1758  		givenFsBidderInfos            BidderInfos
  1759  		givenNillableFieldBidderInfos nillableFieldBidderInfos
  1760  		expectedError                 string
  1761  		expectedBidderInfos           BidderInfos
  1762  	}{
  1763  		{
  1764  			description: "Bidder doesn't exists in bidder list",
  1765  			givenNillableFieldBidderInfos: nillableFieldBidderInfos{"unknown": nillableFieldBidderInfo{
  1766  				bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}},
  1767  			}},
  1768  			expectedError: "error setting configuration for bidder unknown: unknown bidder",
  1769  		},
  1770  		{
  1771  			description:        "Bidder doesn't exists in file system",
  1772  			givenFsBidderInfos: BidderInfos{"unknown": {Endpoint: "original"}},
  1773  			givenNillableFieldBidderInfos: nillableFieldBidderInfos{"bidderA": nillableFieldBidderInfo{
  1774  				bidderInfo: BidderInfo{Syncer: &Syncer{Key: "override"}},
  1775  			}},
  1776  			expectedError: "error finding configuration for bidder bidderA: unknown bidder",
  1777  		},
  1778  	}
  1779  	for _, test := range testCases {
  1780  
  1781  		_, err := applyBidderInfoConfigOverrides(test.givenNillableFieldBidderInfos, test.givenFsBidderInfos, mockNormalizeBidderName)
  1782  		assert.ErrorContains(t, err, test.expectedError, test.description+":err")
  1783  	}
  1784  }
  1785  
  1786  func TestReadFullYamlBidderConfig(t *testing.T) {
  1787  	bidder := "bidderA"
  1788  	bidderInf := BidderInfo{}
  1789  
  1790  	err := yaml.Unmarshal([]byte(fullBidderYAMLConfig), &bidderInf)
  1791  	require.NoError(t, err)
  1792  
  1793  	bidderInfoOverrides := nillableFieldBidderInfos{
  1794  		bidder: nillableFieldBidderInfo{
  1795  			bidderInfo: bidderInf,
  1796  			nillableFields: bidderInfoNillableFields{
  1797  				Disabled:                &bidderInf.Disabled,
  1798  				ModifyingVastXmlAllowed: &bidderInf.ModifyingVastXmlAllowed,
  1799  			},
  1800  		},
  1801  	}
  1802  	bidderInfoBase := BidderInfos{
  1803  		bidder: {Syncer: &Syncer{Supports: []string{"iframe"}}},
  1804  	}
  1805  	actualBidderInfo, err := applyBidderInfoConfigOverrides(bidderInfoOverrides, bidderInfoBase, mockNormalizeBidderName)
  1806  	require.NoError(t, err)
  1807  
  1808  	expectedBidderInfo := BidderInfos{
  1809  		bidder: {
  1810  			Maintainer: &MaintainerInfo{
  1811  				Email: "some-email@domain.com",
  1812  			},
  1813  			GVLVendorID: 42,
  1814  			Capabilities: &CapabilitiesInfo{
  1815  				App: &PlatformInfo{
  1816  					MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
  1817  				},
  1818  				Site: &PlatformInfo{
  1819  					MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo, openrtb_ext.BidTypeNative},
  1820  				},
  1821  				DOOH: &PlatformInfo{
  1822  					MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
  1823  				},
  1824  			},
  1825  			ModifyingVastXmlAllowed: true,
  1826  			Debug: &DebugInfo{
  1827  				Allow: true,
  1828  			},
  1829  			Experiment: BidderInfoExperiment{
  1830  				AdsCert: BidderAdsCert{
  1831  					Enabled: true,
  1832  				},
  1833  			},
  1834  			EndpointCompression: "GZIP",
  1835  			OpenRTB: &OpenRTBInfo{
  1836  				GPPSupported: true,
  1837  				Version:      "2.6",
  1838  			},
  1839  			Disabled:         false,
  1840  			ExtraAdapterInfo: "extra-info",
  1841  			AppSecret:        "app-secret",
  1842  			PlatformID:       "123",
  1843  			Syncer: &Syncer{
  1844  				Key: "foo",
  1845  				IFrame: &SyncerEndpoint{
  1846  					URL:         "https://foo.com/sync?mode=iframe&r={{.RedirectURL}}",
  1847  					RedirectURL: "https://redirect/setuid/iframe",
  1848  					ExternalURL: "https://iframe.host",
  1849  					UserMacro:   "UID",
  1850  				},
  1851  				Supports: []string{"iframe"},
  1852  			},
  1853  			XAPI: AdapterXAPI{
  1854  				Username: "uname",
  1855  				Password: "pwd",
  1856  				Tracker:  "tracker",
  1857  			},
  1858  			Endpoint: "https://endpoint.com",
  1859  		},
  1860  	}
  1861  	assert.Equalf(t, expectedBidderInfo, actualBidderInfo, "Bidder info objects aren't matching")
  1862  }