github.com/prebid/prebid-server@v0.275.0/adapters/rubicon/rubicon_test.go (about)

     1  package rubicon
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"strconv"
     9  	"testing"
    10  
    11  	"github.com/prebid/prebid-server/adapters"
    12  	"github.com/prebid/prebid-server/adapters/adapterstest"
    13  	"github.com/prebid/prebid-server/config"
    14  	"github.com/prebid/prebid-server/errortypes"
    15  	"github.com/prebid/prebid-server/openrtb_ext"
    16  
    17  	"github.com/buger/jsonparser"
    18  	"github.com/prebid/openrtb/v19/adcom1"
    19  	"github.com/prebid/openrtb/v19/openrtb2"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/mock"
    22  )
    23  
    24  type rubiAppendTrackerUrlTestScenario struct {
    25  	source   string
    26  	tracker  string
    27  	expected string
    28  }
    29  
    30  type rubiPopulateFpdAttributesScenario struct {
    31  	source json.RawMessage
    32  	target map[string]interface{}
    33  	result map[string]interface{}
    34  }
    35  
    36  type rubiSetNetworkIdTestScenario struct {
    37  	bidExt            *openrtb_ext.ExtBidPrebid
    38  	buyer             string
    39  	expectedNetworkId int64
    40  	isNetworkIdSet    bool
    41  }
    42  
    43  type rubiBidInfo struct {
    44  	domain        string
    45  	page          string
    46  	deviceIP      string
    47  	deviceUA      string
    48  	buyerUID      string
    49  	devicePxRatio float64
    50  }
    51  
    52  var rubidata rubiBidInfo
    53  
    54  func TestAppendTracker(t *testing.T) {
    55  	testScenarios := []rubiAppendTrackerUrlTestScenario{
    56  		{
    57  			source:   "http://test.url/",
    58  			tracker:  "prebid",
    59  			expected: "http://test.url/?tk_xint=prebid",
    60  		},
    61  		{
    62  			source:   "http://test.url/?hello=true",
    63  			tracker:  "prebid",
    64  			expected: "http://test.url/?hello=true&tk_xint=prebid",
    65  		},
    66  	}
    67  
    68  	for _, scenario := range testScenarios {
    69  		res := appendTrackerToUrl(scenario.source, scenario.tracker)
    70  		assert.Equal(t, scenario.expected, res, "Failed to convert '%s' to '%s'", res, scenario.expected)
    71  	}
    72  }
    73  
    74  func TestSetImpNative(t *testing.T) {
    75  	testScenarios := []struct {
    76  		request       string
    77  		impNative     map[string]interface{}
    78  		expectedError error
    79  	}{
    80  		{
    81  			request:       "{}",
    82  			impNative:     map[string]interface{}{"somekey": "someValue"},
    83  			expectedError: fmt.Errorf("unable to find imp in json data"),
    84  		},
    85  		{
    86  			request:       "{\"imp\":[]}",
    87  			impNative:     map[string]interface{}{"somekey": "someValue"},
    88  			expectedError: fmt.Errorf("unable to find imp[0] in json data"),
    89  		},
    90  		{
    91  			request:       "{\"imp\":[{}]}",
    92  			impNative:     map[string]interface{}{"somekey": "someValue"},
    93  			expectedError: fmt.Errorf("unable to find imp[0].native in json data"),
    94  		},
    95  	}
    96  	for _, scenario := range testScenarios {
    97  		_, err := setImpNative([]byte(scenario.request), scenario.impNative)
    98  		assert.Equal(t, scenario.expectedError, err)
    99  	}
   100  }
   101  
   102  func TestResolveNativeObject(t *testing.T) {
   103  	testScenarios := []struct {
   104  		nativeObject  openrtb2.Native
   105  		target        map[string]interface{}
   106  		expectedError error
   107  	}{
   108  		{
   109  			nativeObject:  openrtb2.Native{Ver: "1.0", Request: "{\"eventtrackers\": \"someWrongValue\"}"},
   110  			target:        map[string]interface{}{},
   111  			expectedError: nil,
   112  		},
   113  		{
   114  			nativeObject:  openrtb2.Native{Ver: "1.1", Request: "{\"eventtrackers\": \"someWrongValue\"}"},
   115  			target:        map[string]interface{}{},
   116  			expectedError: nil,
   117  		},
   118  		{
   119  			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": \"someWrongValue\"}"},
   120  			target:        map[string]interface{}{},
   121  			expectedError: fmt.Errorf("Eventtrackers are not present or not of array type"),
   122  		},
   123  		{
   124  			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": [], \"context\": \"someWrongValue\"}"},
   125  			target:        map[string]interface{}{},
   126  			expectedError: fmt.Errorf("Context is not of int type"),
   127  		},
   128  		{
   129  			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": [], \"plcmttype\": 2}"},
   130  			target:        map[string]interface{}{},
   131  			expectedError: nil,
   132  		},
   133  		{
   134  			nativeObject:  openrtb2.Native{Ver: "1", Request: "{\"eventtrackers\": [], \"context\": 1}"},
   135  			target:        map[string]interface{}{},
   136  			expectedError: fmt.Errorf("Plcmttype is not present or not of int type"),
   137  		},
   138  	}
   139  	for _, scenario := range testScenarios {
   140  		_, err := resolveNativeObject(&scenario.nativeObject, scenario.target)
   141  		assert.Equal(t, scenario.expectedError, err)
   142  	}
   143  }
   144  
   145  func TestResolveVideoSizeId(t *testing.T) {
   146  	testScenarios := []struct {
   147  		placement   adcom1.VideoPlacementSubtype
   148  		instl       int8
   149  		impId       string
   150  		expected    int
   151  		expectedErr error
   152  	}{
   153  		{
   154  			placement:   1,
   155  			instl:       1,
   156  			impId:       "impId",
   157  			expected:    201,
   158  			expectedErr: nil,
   159  		},
   160  		{
   161  			placement:   3,
   162  			instl:       1,
   163  			impId:       "impId",
   164  			expected:    203,
   165  			expectedErr: nil,
   166  		},
   167  		{
   168  			placement:   4,
   169  			instl:       1,
   170  			impId:       "impId",
   171  			expected:    202,
   172  			expectedErr: nil,
   173  		},
   174  		{
   175  			placement: 4,
   176  			instl:     3,
   177  			impId:     "impId",
   178  			expectedErr: &errortypes.BadInput{
   179  				Message: "video.size_id can not be resolved in impression with id : impId",
   180  			},
   181  		},
   182  	}
   183  
   184  	for _, scenario := range testScenarios {
   185  		res, err := resolveVideoSizeId(scenario.placement, scenario.instl, scenario.impId)
   186  		assert.Equal(t, scenario.expected, res)
   187  		assert.Equal(t, scenario.expectedErr, err)
   188  	}
   189  }
   190  
   191  func TestOpenRTBRequestWithDifferentBidFloorAttributes(t *testing.T) {
   192  	testScenarios := []struct {
   193  		bidFloor         float64
   194  		bidFloorCur      string
   195  		setMock          func(m *mock.Mock)
   196  		expectedBidFloor float64
   197  		expectedBidCur   string
   198  		expectedErrors   []error
   199  	}{
   200  		{
   201  			bidFloor:         1,
   202  			bidFloorCur:      "WRONG",
   203  			setMock:          func(m *mock.Mock) { m.On("GetRate", "WRONG", "USD").Return(2.5, errors.New("some error")) },
   204  			expectedBidFloor: 0,
   205  			expectedBidCur:   "",
   206  			expectedErrors: []error{
   207  				&errortypes.BadInput{Message: "Unable to convert provided bid floor currency from WRONG to USD"},
   208  			},
   209  		},
   210  		{
   211  			bidFloor:         1,
   212  			bidFloorCur:      "USD",
   213  			setMock:          func(m *mock.Mock) {},
   214  			expectedBidFloor: 1,
   215  			expectedBidCur:   "USD",
   216  			expectedErrors:   nil,
   217  		},
   218  		{
   219  			bidFloor:         1,
   220  			bidFloorCur:      "EUR",
   221  			setMock:          func(m *mock.Mock) { m.On("GetRate", "EUR", "USD").Return(1.2, nil) },
   222  			expectedBidFloor: 1.2,
   223  			expectedBidCur:   "USD",
   224  			expectedErrors:   nil,
   225  		},
   226  		{
   227  			bidFloor:         0,
   228  			bidFloorCur:      "",
   229  			setMock:          func(m *mock.Mock) {},
   230  			expectedBidFloor: 0,
   231  			expectedBidCur:   "",
   232  			expectedErrors:   nil,
   233  		},
   234  		{
   235  			bidFloor:         -1,
   236  			bidFloorCur:      "CZK",
   237  			setMock:          func(m *mock.Mock) {},
   238  			expectedBidFloor: -1,
   239  			expectedBidCur:   "CZK",
   240  			expectedErrors:   nil,
   241  		},
   242  	}
   243  
   244  	for _, scenario := range testScenarios {
   245  		mockConversions := &mockCurrencyConversion{}
   246  		scenario.setMock(&mockConversions.Mock)
   247  
   248  		extraRequestInfo := adapters.ExtraRequestInfo{
   249  			CurrencyConversions: mockConversions,
   250  		}
   251  
   252  		bidder := new(RubiconAdapter)
   253  
   254  		request := &openrtb2.BidRequest{
   255  			ID: "test-request-id",
   256  			Imp: []openrtb2.Imp{{
   257  				ID:          "test-imp-id",
   258  				BidFloorCur: scenario.bidFloorCur,
   259  				BidFloor:    scenario.bidFloor,
   260  				Banner: &openrtb2.Banner{
   261  					Format: []openrtb2.Format{
   262  						{W: 300, H: 250},
   263  					},
   264  				},
   265  				Ext: json.RawMessage(`{"bidder": {
   266  										"zoneId": 8394,
   267  										"siteId": 283282,
   268  										"accountId": 7891
   269                                        }}`),
   270  			}},
   271  			App: &openrtb2.App{
   272  				ID:   "com.test",
   273  				Name: "testApp",
   274  			},
   275  		}
   276  
   277  		reqs, errs := bidder.MakeRequests(request, &extraRequestInfo)
   278  
   279  		mockConversions.AssertExpectations(t)
   280  
   281  		if scenario.expectedErrors == nil {
   282  			rubiconReq := &openrtb2.BidRequest{}
   283  			if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   284  				t.Fatalf("Unexpected error while decoding request: %s", err)
   285  			}
   286  			assert.Equal(t, scenario.expectedBidFloor, rubiconReq.Imp[0].BidFloor)
   287  			assert.Equal(t, scenario.expectedBidCur, rubiconReq.Imp[0].BidFloorCur)
   288  		} else {
   289  			assert.Equal(t, scenario.expectedErrors, errs)
   290  		}
   291  	}
   292  }
   293  
   294  type mockCurrencyConversion struct {
   295  	mock.Mock
   296  }
   297  
   298  func (m *mockCurrencyConversion) GetRate(from string, to string) (float64, error) {
   299  	args := m.Called(from, to)
   300  	return args.Get(0).(float64), args.Error(1)
   301  }
   302  
   303  func (m *mockCurrencyConversion) GetRates() *map[string]map[string]float64 {
   304  	args := m.Called()
   305  	return args.Get(0).(*map[string]map[string]float64)
   306  }
   307  
   308  func TestOpenRTBRequest(t *testing.T) {
   309  	bidder := new(RubiconAdapter)
   310  
   311  	rubidata = rubiBidInfo{
   312  		domain:        "nytimes.com",
   313  		page:          "https://www.nytimes.com/2017/05/04/movies/guardians-of-the-galaxy-2-review-chris-pratt.html?hpw&rref=movies&action=click&pgtype=Homepage&module=well-region&region=bottom-well&WT.nav=bottom-well&_r=0",
   314  		deviceIP:      "25.91.96.36",
   315  		deviceUA:      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.1 Safari/603.1.30",
   316  		buyerUID:      "need-an-actual-rp-id",
   317  		devicePxRatio: 4.0,
   318  	}
   319  
   320  	request := &openrtb2.BidRequest{
   321  		ID: "test-request-id",
   322  		Imp: []openrtb2.Imp{{
   323  			ID: "test-imp-banner-id",
   324  			Banner: &openrtb2.Banner{
   325  				Format: []openrtb2.Format{
   326  					{W: 300, H: 250},
   327  					{W: 300, H: 600},
   328  				},
   329  			},
   330  			Ext: json.RawMessage(`{"bidder": {
   331  				"zoneId": 8394,
   332  				"siteId": 283282,
   333  				"accountId": 7891,
   334  				"inventory": {"key1" : "val1"},
   335  				"visitor": {"key2" : "val2"}
   336  			}}`),
   337  		}, {
   338  			ID: "test-imp-video-id",
   339  			Video: &openrtb2.Video{
   340  				W:           640,
   341  				H:           360,
   342  				MIMEs:       []string{"video/mp4"},
   343  				MinDuration: 15,
   344  				MaxDuration: 30,
   345  			},
   346  			Ext: json.RawMessage(`{"bidder": {
   347  				"zoneId": 7780,
   348  				"siteId": 283282,
   349  				"accountId": 7891,
   350  				"inventory": {"key1" : "val1"},
   351  				"visitor": {"key2" : "val2"},
   352  				"video": {
   353  					"language": "en",
   354  					"playerHeight": 360,
   355  					"playerWidth": 640,
   356  					"size_id": 203,
   357  					"skip": 1,
   358  					"skipdelay": 5
   359  				}
   360  			}}`),
   361  		}},
   362  		App: &openrtb2.App{
   363  			ID:   "com.test",
   364  			Name: "testApp",
   365  		},
   366  		Device: &openrtb2.Device{
   367  			PxRatio: rubidata.devicePxRatio,
   368  		},
   369  		User: &openrtb2.User{
   370  			Ext: json.RawMessage(`{
   371  				"eids": [{
   372                      "source": "pubcid",
   373  					"uids": [{"id": "2402fc76-7b39-4f0e-bfc2-060ef7693648"}]
   374  				}]
   375              }`),
   376  		},
   377  		Ext: json.RawMessage(`{"prebid": {}}`),
   378  	}
   379  
   380  	reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   381  
   382  	assert.Empty(t, errs, "Got unexpected errors while building HTTP requests: %v", errs)
   383  	assert.Equal(t, 2, len(reqs), "Unexpected number of HTTP requests. Got %d. Expected %d", len(reqs), 2)
   384  
   385  	for i := 0; i < len(reqs); i++ {
   386  		httpReq := reqs[i]
   387  		assert.Equal(t, "POST", httpReq.Method, "Expected a POST message. Got %s", httpReq.Method)
   388  
   389  		var rpRequest openrtb2.BidRequest
   390  		if err := json.Unmarshal(httpReq.Body, &rpRequest); err != nil {
   391  			t.Fatalf("Failed to unmarshal HTTP request: %v", rpRequest)
   392  		}
   393  
   394  		assert.Equal(t, request.ID, rpRequest.ID, "Bad Request ID. Expected %s, Got %s", request.ID, rpRequest.ID)
   395  		assert.Equal(t, 1, len(rpRequest.Imp), "Wrong len(request.Imp). Expected %d, Got %d", len(request.Imp), len(rpRequest.Imp))
   396  		assert.Nil(t, rpRequest.Cur, "Wrong request.Cur. Expected nil, Got %s", rpRequest.Cur)
   397  		assert.Nil(t, rpRequest.Ext, "Wrong request.ext. Expected nil, Got %v", rpRequest.Ext)
   398  
   399  		if rpRequest.Imp[0].ID == "test-imp-banner-id" {
   400  			var rpExt rubiconBannerExt
   401  			if err := json.Unmarshal(rpRequest.Imp[0].Ext, &rpExt); err != nil {
   402  				t.Fatal("Error unmarshalling request from the outgoing request.")
   403  			}
   404  
   405  			assert.Equal(t, int64(300), rpRequest.Imp[0].Banner.Format[0].W,
   406  				"Banner width does not match. Expected %d, Got %d", 300, rpRequest.Imp[0].Banner.Format[0].W)
   407  
   408  			assert.Equal(t, int64(250), rpRequest.Imp[0].Banner.Format[0].H,
   409  				"Banner height does not match. Expected %d, Got %d", 250, rpRequest.Imp[0].Banner.Format[0].H)
   410  
   411  			assert.Equal(t, int64(300), rpRequest.Imp[0].Banner.Format[1].W,
   412  				"Banner width does not match. Expected %d, Got %d", 300, rpRequest.Imp[0].Banner.Format[1].W)
   413  
   414  			assert.Equal(t, int64(600), rpRequest.Imp[0].Banner.Format[1].H,
   415  				"Banner height does not match. Expected %d, Got %d", 600, rpRequest.Imp[0].Banner.Format[1].H)
   416  		} else if rpRequest.Imp[0].ID == "test-imp-video-id" {
   417  			var rpExt rubiconVideoExt
   418  			if err := json.Unmarshal(rpRequest.Imp[0].Ext, &rpExt); err != nil {
   419  				t.Fatal("Error unmarshalling request from the outgoing request.")
   420  			}
   421  
   422  			assert.Equal(t, int64(640), rpRequest.Imp[0].Video.W,
   423  				"Video width does not match. Expected %d, Got %d", 640, rpRequest.Imp[0].Video.W)
   424  
   425  			assert.Equal(t, int64(360), rpRequest.Imp[0].Video.H,
   426  				"Video height does not match. Expected %d, Got %d", 360, rpRequest.Imp[0].Video.H)
   427  
   428  			assert.Equal(t, "video/mp4", rpRequest.Imp[0].Video.MIMEs[0], "Video MIMEs do not match. Expected %s, Got %s", "video/mp4", rpRequest.Imp[0].Video.MIMEs[0])
   429  
   430  			assert.Equal(t, int64(15), rpRequest.Imp[0].Video.MinDuration,
   431  				"Video min duration does not match. Expected %d, Got %d", 15, rpRequest.Imp[0].Video.MinDuration)
   432  
   433  			assert.Equal(t, int64(30), rpRequest.Imp[0].Video.MaxDuration,
   434  				"Video max duration does not match. Expected %d, Got %d", 30, rpRequest.Imp[0].Video.MaxDuration)
   435  		}
   436  
   437  		assert.NotNil(t, rpRequest.User.Ext, "User.Ext object should not be nil.")
   438  
   439  		var userExt rubiconUserExt
   440  		if err := json.Unmarshal(rpRequest.User.Ext, &userExt); err != nil {
   441  			t.Fatal("Error unmarshalling request.user.ext object.")
   442  		}
   443  
   444  		assert.NotNil(t, userExt.Eids)
   445  		assert.Equal(t, 1, len(userExt.Eids), "Eids values are not as expected!")
   446  		assert.Contains(t, userExt.Eids, openrtb2.EID{Source: "pubcid", UIDs: []openrtb2.UID{{ID: "2402fc76-7b39-4f0e-bfc2-060ef7693648"}}})
   447  	}
   448  }
   449  
   450  func TestOpenRTBRequestWithBannerImpEvenIfImpHasVideo(t *testing.T) {
   451  	bidder := new(RubiconAdapter)
   452  
   453  	request := &openrtb2.BidRequest{
   454  		ID: "test-request-id",
   455  		Imp: []openrtb2.Imp{{
   456  			ID: "test-imp-id",
   457  			Banner: &openrtb2.Banner{
   458  				Format: []openrtb2.Format{
   459  					{W: 300, H: 250},
   460  				},
   461  			},
   462  			Video: &openrtb2.Video{
   463  				W:     640,
   464  				H:     360,
   465  				MIMEs: []string{"video/mp4"},
   466  			},
   467  			Ext: json.RawMessage(`{"bidder": {
   468  				"zoneId": 8394,
   469  				"siteId": 283282,
   470  				"accountId": 7891,
   471  				"inventory": {"key1" : "val1"},
   472  				"visitor": {"key2" : "val2"}
   473  			}}`),
   474  		}},
   475  		App: &openrtb2.App{
   476  			ID:   "com.test",
   477  			Name: "testApp",
   478  		},
   479  	}
   480  
   481  	reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   482  
   483  	assert.Empty(t, errs, "Got unexpected errors while building HTTP requests: %v", errs)
   484  
   485  	assert.Equal(t, 1, len(reqs), "Unexpected number of HTTP requests. Got %d. Expected %d", len(reqs), 1)
   486  
   487  	rubiconReq := &openrtb2.BidRequest{}
   488  	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   489  		t.Fatalf("Unexpected error while decoding request: %s", err)
   490  	}
   491  
   492  	assert.Equal(t, 1, len(rubiconReq.Imp), "Unexpected number of request impressions. Got %d. Expected %d", len(rubiconReq.Imp), 1)
   493  
   494  	assert.Nil(t, rubiconReq.Imp[0].Video, "Unexpected video object in request impression")
   495  
   496  	assert.NotNil(t, rubiconReq.Imp[0].Banner, "Banner object must be in request impression")
   497  }
   498  
   499  func TestOpenRTBRequestWithImpAndAdSlotIncluded(t *testing.T) {
   500  	bidder := new(RubiconAdapter)
   501  
   502  	request := &openrtb2.BidRequest{
   503  		ID: "test-request-id",
   504  		Imp: []openrtb2.Imp{{
   505  			ID: "test-imp-id",
   506  			Banner: &openrtb2.Banner{
   507  				Format: []openrtb2.Format{
   508  					{W: 300, H: 250},
   509  				},
   510  			},
   511  			Ext: json.RawMessage(`{
   512  				"bidder": {
   513  					"zoneId": 8394,
   514  					"siteId": 283282,
   515  					"accountId": 7891,
   516  					"inventory": {"key1" : "val1"},
   517  					"visitor": {"key2" : "val2"}
   518  				},
   519  				"context": {
   520  					"data": {
   521                          "adserver": {
   522                               "adslot": "/test-adslot",
   523                               "name": "gam"
   524                          }
   525  					}
   526  				}
   527  			}`),
   528  		}},
   529  		App: &openrtb2.App{
   530  			ID:   "com.test",
   531  			Name: "testApp",
   532  		},
   533  	}
   534  
   535  	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   536  
   537  	rubiconReq := &openrtb2.BidRequest{}
   538  	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   539  		t.Fatalf("Unexpected error while decoding request: %s", err)
   540  	}
   541  
   542  	assert.Equal(t, 1, len(rubiconReq.Imp),
   543  		"Unexpected number of request impressions. Got %d. Expected %d", len(rubiconReq.Imp), 1)
   544  
   545  	var rpImpExt rubiconImpExt
   546  	if err := json.Unmarshal(rubiconReq.Imp[0].Ext, &rpImpExt); err != nil {
   547  		t.Fatal("Error unmarshalling imp.ext")
   548  	}
   549  
   550  	dfpAdUnitCode, err := jsonparser.GetString(rpImpExt.RP.Target, "dfp_ad_unit_code")
   551  	if err != nil {
   552  		t.Fatal("Error extracting dfp_ad_unit_code")
   553  	}
   554  	assert.Equal(t, dfpAdUnitCode, "/test-adslot")
   555  }
   556  
   557  func TestOpenRTBFirstPartyDataPopulating(t *testing.T) {
   558  	testScenarios := []rubiPopulateFpdAttributesScenario{
   559  		{
   560  			source: json.RawMessage(`{"sourceKey": ["sourceValue", "sourceValue2"]}`),
   561  			target: map[string]interface{}{"targetKey": []interface{}{"targetValue"}},
   562  			result: map[string]interface{}{"targetKey": []interface{}{"targetValue"}, "sourceKey": []interface{}{"sourceValue", "sourceValue2"}},
   563  		},
   564  		{
   565  			source: json.RawMessage(`{"sourceKey": ["sourceValue", "sourceValue2"]}`),
   566  			target: make(map[string]interface{}),
   567  			result: map[string]interface{}{"sourceKey": []interface{}{"sourceValue", "sourceValue2"}},
   568  		},
   569  		{
   570  			source: json.RawMessage(`{"sourceKey": "sourceValue"}`),
   571  			target: make(map[string]interface{}),
   572  			result: map[string]interface{}{"sourceKey": [1]string{"sourceValue"}},
   573  		},
   574  		{
   575  			source: json.RawMessage(`{"sourceKey": true, "sourceKey2": [true, false, true]}`),
   576  			target: make(map[string]interface{}),
   577  			result: map[string]interface{}{"sourceKey": [1]string{"true"}, "sourceKey2": []string{"true", "false", "true"}},
   578  		},
   579  		{
   580  			source: json.RawMessage(`{"sourceKey": 1, "sourceKey2": [1, 2, 3]}`),
   581  			target: make(map[string]interface{}),
   582  			result: map[string]interface{}{"sourceKey": [1]string{"1"}},
   583  		},
   584  		{
   585  			source: json.RawMessage(`{"sourceKey": 1, "sourceKey2": 3.23}`),
   586  			target: make(map[string]interface{}),
   587  			result: map[string]interface{}{"sourceKey": [1]string{"1"}},
   588  		},
   589  		{
   590  			source: json.RawMessage(`{"sourceKey": {}}`),
   591  			target: make(map[string]interface{}),
   592  			result: make(map[string]interface{}),
   593  		},
   594  	}
   595  
   596  	for _, scenario := range testScenarios {
   597  		populateFirstPartyDataAttributes(scenario.source, scenario.target)
   598  		assert.Equal(t, scenario.result, scenario.target)
   599  	}
   600  }
   601  
   602  func TestOpenRTBRequestWithBadvOverflowed(t *testing.T) {
   603  	bidder := new(RubiconAdapter)
   604  
   605  	badvOverflowed := make([]string, 100)
   606  	for i := range badvOverflowed {
   607  		badvOverflowed[i] = strconv.Itoa(i)
   608  	}
   609  
   610  	request := &openrtb2.BidRequest{
   611  		ID:   "test-request-id",
   612  		BAdv: badvOverflowed,
   613  		Imp: []openrtb2.Imp{{
   614  			ID: "test-imp-id",
   615  			Banner: &openrtb2.Banner{
   616  				Format: []openrtb2.Format{
   617  					{W: 300, H: 250},
   618  				},
   619  			},
   620  			Ext: json.RawMessage(`{
   621  				"bidder": {
   622  					"zoneId": 8394,
   623  					"siteId": 283282,
   624  					"accountId": 7891,
   625  					"inventory": {"key1" : "val1"},
   626  					"visitor": {"key2" : "val2"}
   627  				}
   628  			}`),
   629  		}},
   630  		App: &openrtb2.App{
   631  			ID:   "com.test",
   632  			Name: "testApp",
   633  		},
   634  	}
   635  
   636  	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   637  
   638  	rubiconReq := &openrtb2.BidRequest{}
   639  	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   640  		t.Fatalf("Unexpected error while decoding request: %s", err)
   641  	}
   642  
   643  	badvRequest := rubiconReq.BAdv
   644  	assert.Equal(t, badvOverflowed[:50], badvRequest, "Unexpected dfp_ad_unit_code: %s")
   645  }
   646  
   647  func TestOpenRTBRequestWithSpecificExtUserEids(t *testing.T) {
   648  	bidder := new(RubiconAdapter)
   649  
   650  	request := &openrtb2.BidRequest{
   651  		ID: "test-request-id",
   652  		Imp: []openrtb2.Imp{{
   653  			ID: "test-imp-id",
   654  			Banner: &openrtb2.Banner{
   655  				Format: []openrtb2.Format{
   656  					{W: 300, H: 250},
   657  				},
   658  			},
   659  			Ext: json.RawMessage(`{"bidder": {
   660  				"zoneId": 8394,
   661  				"siteId": 283282,
   662  				"accountId": 7891
   663  			}}`),
   664  		}},
   665  		App: &openrtb2.App{
   666  			ID:   "com.test",
   667  			Name: "testApp",
   668  		},
   669  		User: &openrtb2.User{
   670  			Ext: json.RawMessage(`{"eids": [
   671  			{
   672  				"source": "pubcid",
   673  				"uids": [{
   674  					"id": "2402fc76-7b39-4f0e-bfc2-060ef7693648"
   675  				}]
   676  			},
   677  			{
   678  				"source": "adserver.org",
   679  				"uids": [{
   680  					"id": "3d50a262-bd8e-4be3-90b8-246291523907",
   681  					"ext": {
   682  						"rtiPartner": "TDID"
   683  					}
   684  				}]
   685  			},
   686  			{
   687  				"source": "liveintent.com",
   688  				"uids": [{
   689  					"id": "T7JiRRvsRAmh88"
   690  				}],
   691  				"ext": {
   692  					"segments": ["999","888"]
   693  				}
   694  			},
   695  			{
   696  				"source": "liveramp.com",
   697  				"uids": [{
   698  					"id": "LIVERAMPID"
   699  				}],
   700  				"ext": {
   701  					"segments": ["111","222"]
   702  				}
   703  			}
   704  			]}`),
   705  		},
   706  	}
   707  
   708  	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   709  
   710  	rubiconReq := &openrtb2.BidRequest{}
   711  	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   712  		t.Fatalf("Unexpected error while decoding request: %s", err)
   713  	}
   714  
   715  	assert.NotNil(t, rubiconReq.User.Ext, "User.Ext object should not be nil.")
   716  
   717  	var userExt rubiconUserExt
   718  	if err := json.Unmarshal(rubiconReq.User.Ext, &userExt); err != nil {
   719  		t.Fatal("Error unmarshalling request.user.ext object.")
   720  	}
   721  
   722  	assert.NotNil(t, userExt.Eids)
   723  	assert.Equal(t, 4, len(userExt.Eids), "Eids values are not as expected!")
   724  
   725  	// liveramp.com
   726  	assert.Equal(t, "LIVERAMPID", userExt.LiverampIdl, "Liveramp_idl value is not as expected!")
   727  
   728  	userExtRPTarget := make(map[string]interface{})
   729  	if err := json.Unmarshal(userExt.RP.Target, &userExtRPTarget); err != nil {
   730  		t.Fatal("Error unmarshalling request.user.ext.rp.target object.")
   731  	}
   732  
   733  	assert.Contains(t, userExtRPTarget, "LIseg", "request.user.ext.rp.target value is not as expected!")
   734  	assert.Contains(t, userExtRPTarget["LIseg"], "888", "No segment with 888 as expected!")
   735  	assert.Contains(t, userExtRPTarget["LIseg"], "999", "No segment with 999 as expected!")
   736  }
   737  
   738  func TestOpenRTBRequestWithVideoImpEvenIfImpHasBannerButAllRequiredVideoFields(t *testing.T) {
   739  	bidder := new(RubiconAdapter)
   740  
   741  	request := &openrtb2.BidRequest{
   742  		ID: "test-request-id",
   743  		Imp: []openrtb2.Imp{{
   744  			ID: "test-imp-id",
   745  			Banner: &openrtb2.Banner{
   746  				Format: []openrtb2.Format{
   747  					{W: 300, H: 250},
   748  				},
   749  			},
   750  			Video: &openrtb2.Video{
   751  				W:           640,
   752  				H:           360,
   753  				MIMEs:       []string{"video/mp4"},
   754  				Protocols:   []adcom1.MediaCreativeSubtype{adcom1.CreativeVAST10},
   755  				MaxDuration: 30,
   756  				Linearity:   1,
   757  				API:         []adcom1.APIFramework{},
   758  			},
   759  			Ext: json.RawMessage(`{"bidder": {
   760  				"zoneId": 8394,
   761  				"siteId": 283282,
   762  				"accountId": 7891,
   763  				"inventory": {"key1": "val1"},
   764  				"visitor": {"key2": "val2"},
   765  				"video": {"size_id": 1}
   766  			}}`),
   767  		}},
   768  		App: &openrtb2.App{
   769  			ID:   "com.test",
   770  			Name: "testApp",
   771  		},
   772  	}
   773  
   774  	reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   775  
   776  	assert.Empty(t, errs, "Got unexpected errors while building HTTP requests: %v", errs)
   777  
   778  	assert.Equal(t, 1, len(reqs), "Unexpected number of HTTP requests. Got %d. Expected %d", len(reqs), 1)
   779  
   780  	rubiconReq := &openrtb2.BidRequest{}
   781  	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   782  		t.Fatalf("Unexpected error while decoding request: %s", err)
   783  	}
   784  
   785  	assert.Equal(t, 1, len(rubiconReq.Imp),
   786  		"Unexpected number of request impressions. Got %d. Expected %d", len(rubiconReq.Imp), 1)
   787  
   788  	assert.Nil(t, rubiconReq.Imp[0].Banner, "Unexpected banner object in request impression")
   789  
   790  	assert.NotNil(t, rubiconReq.Imp[0].Video, "Video object must be in request impression")
   791  }
   792  
   793  func TestOpenRTBRequestWithVideoImpAndEnabledRewardedInventoryFlag(t *testing.T) {
   794  	bidder := new(RubiconAdapter)
   795  
   796  	request := &openrtb2.BidRequest{
   797  		ID: "test-request-id",
   798  		Imp: []openrtb2.Imp{{
   799  			ID: "test-imp-id",
   800  			Video: &openrtb2.Video{
   801  				W:           640,
   802  				H:           360,
   803  				MIMEs:       []string{"video/mp4"},
   804  				Protocols:   []adcom1.MediaCreativeSubtype{adcom1.CreativeVAST10},
   805  				MaxDuration: 30,
   806  				Linearity:   1,
   807  				API:         []adcom1.APIFramework{},
   808  			},
   809  			Ext: json.RawMessage(`{
   810  			"prebid":{
   811  				"is_rewarded_inventory": 1
   812  			},
   813  			"bidder": {
   814  				"video": {"size_id": 1},
   815  				"zoneId": "123",
   816  				"siteId": 1234,
   817  				"accountId": "444"
   818  			}}`),
   819  		}},
   820  		App: &openrtb2.App{
   821  			ID:   "com.test",
   822  			Name: "testApp",
   823  		},
   824  	}
   825  
   826  	reqs, _ := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})
   827  
   828  	rubiconReq := &openrtb2.BidRequest{}
   829  	if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil {
   830  		t.Fatalf("Unexpected error while decoding request: %s", err)
   831  	}
   832  
   833  	videoExt := &rubiconVideoExt{}
   834  	if err := json.Unmarshal(rubiconReq.Imp[0].Video.Ext, &videoExt); err != nil {
   835  		t.Fatal("Error unmarshalling request.imp[i].video.ext object.")
   836  	}
   837  
   838  	assert.Equal(t, "rewarded", videoExt.VideoType,
   839  		"Unexpected VideoType. Got %s. Expected %s", videoExt.VideoType, "rewarded")
   840  }
   841  
   842  func TestOpenRTBEmptyResponse(t *testing.T) {
   843  	httpResp := &adapters.ResponseData{
   844  		StatusCode: http.StatusNoContent,
   845  	}
   846  	bidder := new(RubiconAdapter)
   847  	bidResponse, errs := bidder.MakeBids(nil, nil, httpResp)
   848  
   849  	assert.Nil(t, bidResponse, "Expected empty response")
   850  	assert.Empty(t, errs, "Expected 0 errors. Got %d", len(errs))
   851  }
   852  
   853  func TestOpenRTBSurpriseResponse(t *testing.T) {
   854  	httpResp := &adapters.ResponseData{
   855  		StatusCode: http.StatusAccepted,
   856  	}
   857  	bidder := new(RubiconAdapter)
   858  	bidResponse, errs := bidder.MakeBids(nil, nil, httpResp)
   859  
   860  	assert.Nil(t, bidResponse, "Expected empty response")
   861  
   862  	assert.Equal(t, 1, len(errs), "Expected 1 error. Got %d", len(errs))
   863  }
   864  
   865  func TestOpenRTBStandardResponse(t *testing.T) {
   866  	request := &openrtb2.BidRequest{
   867  		ID: "test-request-id",
   868  		Imp: []openrtb2.Imp{{
   869  			ID: "test-imp-id",
   870  			Banner: &openrtb2.Banner{
   871  				Format: []openrtb2.Format{{
   872  					W: 320,
   873  					H: 50,
   874  				}},
   875  			},
   876  			Ext: json.RawMessage(`{"bidder": {
   877  				"accountId": 2763,
   878  				"siteId": 68780,
   879  				"zoneId": 327642
   880  			}}`),
   881  		}},
   882  	}
   883  
   884  	requestJson, _ := json.Marshal(request)
   885  	reqData := &adapters.RequestData{
   886  		Method:  "POST",
   887  		Uri:     "test-uri",
   888  		Body:    requestJson,
   889  		Headers: nil,
   890  	}
   891  
   892  	httpResp := &adapters.ResponseData{
   893  		StatusCode: http.StatusOK,
   894  		Body:       []byte(`{"id":"test-request-id","seatbid":[{"bid":[{"id":"1234567890","impid":"test-imp-id","price": 2,"crid":"4122982","adm":"some ad","h": 50,"w": 320,"ext":{"bidder":{"rp":{"targeting": {"key": "rpfl_2763", "values":["43_tier0100"]},"mime": "text/html","size_id": 43}}}}]}]}`),
   895  	}
   896  
   897  	bidder := new(RubiconAdapter)
   898  	bidResponse, errs := bidder.MakeBids(request, reqData, httpResp)
   899  
   900  	assert.NotNil(t, bidResponse, "Expected not empty response")
   901  	assert.Equal(t, 1, len(bidResponse.Bids), "Expected 1 bid. Got %d", len(bidResponse.Bids))
   902  
   903  	assert.Empty(t, errs, "Expected 0 errors. Got %d", len(errs))
   904  
   905  	assert.Equal(t, openrtb_ext.BidTypeBanner, bidResponse.Bids[0].BidType,
   906  		"Expected a banner bid. Got: %s", bidResponse.Bids[0].BidType)
   907  
   908  	theBid := bidResponse.Bids[0].Bid
   909  	assert.Equal(t, "1234567890", theBid.ID, "Bad bid ID. Expected %s, got %s", "1234567890", theBid.ID)
   910  }
   911  
   912  func TestOpenRTBResponseOverridePriceFromBidRequest(t *testing.T) {
   913  	request := &openrtb2.BidRequest{
   914  		ID: "test-request-id",
   915  		Imp: []openrtb2.Imp{{
   916  			ID: "test-imp-id",
   917  			Banner: &openrtb2.Banner{
   918  				Format: []openrtb2.Format{{
   919  					W: 320,
   920  					H: 50,
   921  				}},
   922  			},
   923  			Ext: json.RawMessage(`{"bidder": {
   924  				"accountId": 2763,
   925  				"siteId": 68780,
   926  				"zoneId": 327642
   927  			}}`),
   928  		}},
   929  		Ext: json.RawMessage(`{"prebid": {
   930  			"bidders": {
   931  				"rubicon": {
   932  					"debug": {
   933  						"cpmoverride": 10
   934  			}}}}}`),
   935  	}
   936  
   937  	requestJson, _ := json.Marshal(request)
   938  	reqData := &adapters.RequestData{
   939  		Method:  "POST",
   940  		Uri:     "test-uri",
   941  		Body:    requestJson,
   942  		Headers: nil,
   943  	}
   944  
   945  	httpResp := &adapters.ResponseData{
   946  		StatusCode: http.StatusOK,
   947  		Body:       []byte(`{"id":"test-request-id","seatbid":[{"bid":[{"id":"1234567890","impid":"test-imp-id","price": 2,"crid":"4122982","adm":"some ad","h": 50,"w": 320,"ext":{"bidder":{"rp":{"targeting": {"key": "rpfl_2763", "values":["43_tier0100"]},"mime": "text/html","size_id": 43}}}}]}]}`),
   948  	}
   949  
   950  	bidder := new(RubiconAdapter)
   951  	bidResponse, errs := bidder.MakeBids(request, reqData, httpResp)
   952  
   953  	assert.Empty(t, errs, "Expected 0 errors. Got %d", len(errs))
   954  
   955  	assert.Equal(t, float64(10), bidResponse.Bids[0].Bid.Price,
   956  		"Expected Price 10. Got: %s", bidResponse.Bids[0].Bid.Price)
   957  }
   958  
   959  func TestOpenRTBResponseSettingOfNetworkId(t *testing.T) {
   960  	testScenarios := []rubiSetNetworkIdTestScenario{
   961  		{
   962  			bidExt:            nil,
   963  			buyer:             "1",
   964  			expectedNetworkId: 1,
   965  			isNetworkIdSet:    true,
   966  		},
   967  		{
   968  			bidExt:            nil,
   969  			buyer:             "0",
   970  			expectedNetworkId: 0,
   971  			isNetworkIdSet:    false,
   972  		},
   973  		{
   974  			bidExt:            nil,
   975  			buyer:             "-1",
   976  			expectedNetworkId: 0,
   977  			isNetworkIdSet:    false,
   978  		},
   979  		{
   980  			bidExt:            nil,
   981  			buyer:             "1.1",
   982  			expectedNetworkId: 0,
   983  			isNetworkIdSet:    false,
   984  		},
   985  		{
   986  			bidExt:            &openrtb_ext.ExtBidPrebid{},
   987  			buyer:             "2",
   988  			expectedNetworkId: 2,
   989  			isNetworkIdSet:    true,
   990  		},
   991  		{
   992  			bidExt:            &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{}},
   993  			buyer:             "3",
   994  			expectedNetworkId: 3,
   995  			isNetworkIdSet:    true,
   996  		},
   997  		{
   998  			bidExt:            &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: 5}},
   999  			buyer:             "4",
  1000  			expectedNetworkId: 4,
  1001  			isNetworkIdSet:    true,
  1002  		},
  1003  		{
  1004  			bidExt:            &openrtb_ext.ExtBidPrebid{Meta: &openrtb_ext.ExtBidPrebidMeta{NetworkID: 5}},
  1005  			buyer:             "-1",
  1006  			expectedNetworkId: 5,
  1007  			isNetworkIdSet:    false,
  1008  		},
  1009  	}
  1010  
  1011  	for _, scenario := range testScenarios {
  1012  		request := &openrtb2.BidRequest{
  1013  			Imp: []openrtb2.Imp{{
  1014  				ID:     "test-imp-id",
  1015  				Banner: &openrtb2.Banner{},
  1016  			}},
  1017  		}
  1018  
  1019  		requestJson, _ := json.Marshal(request)
  1020  		reqData := &adapters.RequestData{
  1021  			Method:  "POST",
  1022  			Uri:     "test-uri",
  1023  			Body:    requestJson,
  1024  			Headers: nil,
  1025  		}
  1026  
  1027  		var givenBidExt json.RawMessage
  1028  		if scenario.bidExt != nil {
  1029  			marshalledExt, _ := json.Marshal(scenario.bidExt)
  1030  			givenBidExt = marshalledExt
  1031  		} else {
  1032  			givenBidExt = nil
  1033  		}
  1034  
  1035  		givenBidResponse := rubiconBidResponse{
  1036  			SeatBid: []rubiconSeatBid{{Buyer: scenario.buyer,
  1037  				Bid: []rubiconBid{{
  1038  					Bid: openrtb2.Bid{Price: 123.2, ImpID: "test-imp-id", Ext: givenBidExt}}}}},
  1039  		}
  1040  		body, _ := json.Marshal(&givenBidResponse)
  1041  		httpResp := &adapters.ResponseData{
  1042  			StatusCode: http.StatusOK,
  1043  			Body:       body,
  1044  		}
  1045  
  1046  		bidder := new(RubiconAdapter)
  1047  		bidResponse, errs := bidder.MakeBids(request, reqData, httpResp)
  1048  		assert.Empty(t, errs)
  1049  		if scenario.isNetworkIdSet {
  1050  			networkdId, err := jsonparser.GetInt(bidResponse.Bids[0].Bid.Ext, "prebid", "meta", "networkId")
  1051  			assert.NoError(t, err)
  1052  			assert.Equal(t, scenario.expectedNetworkId, networkdId)
  1053  		} else {
  1054  			assert.Equal(t, bidResponse.Bids[0].Bid.Ext, givenBidExt)
  1055  		}
  1056  	}
  1057  }
  1058  
  1059  func TestOpenRTBResponseOverridePriceFromCorrespondingImp(t *testing.T) {
  1060  	request := &openrtb2.BidRequest{
  1061  		ID: "test-request-id",
  1062  		Imp: []openrtb2.Imp{{
  1063  			ID: "test-imp-id",
  1064  			Banner: &openrtb2.Banner{
  1065  				Format: []openrtb2.Format{{
  1066  					W: 320,
  1067  					H: 50,
  1068  				}},
  1069  			},
  1070  			Ext: json.RawMessage(`{"bidder": {
  1071  				"accountId": 2763,
  1072  				"siteId": 68780,
  1073  				"zoneId": 327642,
  1074  				"debug": {
  1075  					"cpmoverride" : 20 
  1076  				}
  1077  			}}`),
  1078  		}},
  1079  		Ext: json.RawMessage(`{"prebid": {
  1080  			"bidders": {
  1081  				"rubicon": {
  1082  					"debug": {
  1083  						"cpmoverride": 10
  1084  			}}}}}`),
  1085  	}
  1086  
  1087  	requestJson, _ := json.Marshal(request)
  1088  	reqData := &adapters.RequestData{
  1089  		Method:  "POST",
  1090  		Uri:     "test-uri",
  1091  		Body:    requestJson,
  1092  		Headers: nil,
  1093  	}
  1094  
  1095  	httpResp := &adapters.ResponseData{
  1096  		StatusCode: http.StatusOK,
  1097  		Body:       []byte(`{"id":"test-request-id","seatbid":[{"bid":[{"id":"1234567890","impid":"test-imp-id","price": 2,"crid":"4122982","adm":"some ad","h": 50,"w": 320,"ext":{"bidder":{"rp":{"targeting": {"key": "rpfl_2763", "values":["43_tier0100"]},"mime": "text/html","size_id": 43}}}}]}]}`),
  1098  	}
  1099  
  1100  	bidder := new(RubiconAdapter)
  1101  	bidResponse, errs := bidder.MakeBids(request, reqData, httpResp)
  1102  
  1103  	assert.Empty(t, errs, "Expected 0 errors. Got %d", len(errs))
  1104  
  1105  	assert.Equal(t, float64(20), bidResponse.Bids[0].Bid.Price,
  1106  		"Expected Price 20. Got: %s", bidResponse.Bids[0].Bid.Price)
  1107  }
  1108  
  1109  func TestOpenRTBCopyBidIdFromResponseIfZero(t *testing.T) {
  1110  	request := &openrtb2.BidRequest{
  1111  		ID:  "test-request-id",
  1112  		Imp: []openrtb2.Imp{{}},
  1113  	}
  1114  
  1115  	requestJson, _ := json.Marshal(request)
  1116  	reqData := &adapters.RequestData{Body: requestJson}
  1117  
  1118  	httpResp := &adapters.ResponseData{
  1119  		StatusCode: http.StatusOK,
  1120  		Body:       []byte(`{"id":"test-request-id","bidid":"1234567890","seatbid":[{"bid":[{"id":"0","price": 1}]}]}`),
  1121  	}
  1122  
  1123  	bidder := new(RubiconAdapter)
  1124  	bidResponse, _ := bidder.MakeBids(request, reqData, httpResp)
  1125  
  1126  	theBid := bidResponse.Bids[0].Bid
  1127  	assert.Equal(t, "1234567890", theBid.ID, "Bad bid ID. Expected %s, got %s", "1234567890", theBid.ID)
  1128  }
  1129  
  1130  func TestJsonSamples(t *testing.T) {
  1131  	bidder, buildErr := Builder(openrtb_ext.BidderRubicon, config.Adapter{
  1132  		Endpoint: "uri",
  1133  		XAPI: config.AdapterXAPI{
  1134  			Username: "xuser",
  1135  			Password: "xpass",
  1136  			Tracker:  "pbs-test-tracker",
  1137  		}}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
  1138  
  1139  	if buildErr != nil {
  1140  		t.Fatalf("Builder returned unexpected error %v", buildErr)
  1141  	}
  1142  
  1143  	adapterstest.RunJSONBidderTest(t, "rubicontest", bidder)
  1144  }