github.com/prebid/prebid-server/v2@v2.18.0/adapters/pubmatic/pubmatic_test.go (about)

     1  package pubmatic
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  	"sort"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/prebid/openrtb/v20/openrtb2"
    11  	"github.com/prebid/prebid-server/v2/adapters"
    12  	"github.com/prebid/prebid-server/v2/adapters/adapterstest"
    13  	"github.com/prebid/prebid-server/v2/config"
    14  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestJsonSamples(t *testing.T) {
    19  	bidder, buildErr := Builder(openrtb_ext.BidderPubmatic, config.Adapter{
    20  		Endpoint: "https://hbopenbid.pubmatic.com/translator?source=prebid-server"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
    21  
    22  	if buildErr != nil {
    23  		t.Fatalf("Builder returned unexpected error %v", buildErr)
    24  	}
    25  
    26  	adapterstest.RunJSONBidderTest(t, "pubmatictest", bidder)
    27  }
    28  
    29  func TestGetBidTypeVideo(t *testing.T) {
    30  	pubmaticExt := &pubmaticBidExt{}
    31  	pubmaticExt.BidType = new(int)
    32  	*pubmaticExt.BidType = 1
    33  	actualBidTypeValue := getBidType(pubmaticExt)
    34  	if actualBidTypeValue != openrtb_ext.BidTypeVideo {
    35  		t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeVideo, actualBidTypeValue)
    36  	}
    37  }
    38  
    39  func TestGetBidTypeForMissingBidTypeExt(t *testing.T) {
    40  	pubmaticExt := &pubmaticBidExt{}
    41  	actualBidTypeValue := getBidType(pubmaticExt)
    42  	// banner is the default bid type when no bidType key is present in the bid.ext
    43  	if actualBidTypeValue != "banner" {
    44  		t.Errorf("Expected Bid Type value was: banner, actual value is: %v", actualBidTypeValue)
    45  	}
    46  }
    47  
    48  func TestGetBidTypeBanner(t *testing.T) {
    49  	pubmaticExt := &pubmaticBidExt{}
    50  	pubmaticExt.BidType = new(int)
    51  	*pubmaticExt.BidType = 0
    52  	actualBidTypeValue := getBidType(pubmaticExt)
    53  	if actualBidTypeValue != openrtb_ext.BidTypeBanner {
    54  		t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeBanner, actualBidTypeValue)
    55  	}
    56  }
    57  
    58  func TestGetBidTypeNative(t *testing.T) {
    59  	pubmaticExt := &pubmaticBidExt{}
    60  	pubmaticExt.BidType = new(int)
    61  	*pubmaticExt.BidType = 2
    62  	actualBidTypeValue := getBidType(pubmaticExt)
    63  	if actualBidTypeValue != openrtb_ext.BidTypeNative {
    64  		t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeNative, actualBidTypeValue)
    65  	}
    66  }
    67  
    68  func TestGetBidTypeForUnsupportedCode(t *testing.T) {
    69  	pubmaticExt := &pubmaticBidExt{}
    70  	pubmaticExt.BidType = new(int)
    71  	*pubmaticExt.BidType = 99
    72  	actualBidTypeValue := getBidType(pubmaticExt)
    73  	if actualBidTypeValue != openrtb_ext.BidTypeBanner {
    74  		t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeBanner, actualBidTypeValue)
    75  	}
    76  }
    77  
    78  func TestParseImpressionObject(t *testing.T) {
    79  	type args struct {
    80  		imp                      *openrtb2.Imp
    81  		extractWrapperExtFromImp bool
    82  		extractPubIDFromImp      bool
    83  	}
    84  	tests := []struct {
    85  		name                string
    86  		args                args
    87  		expectedWrapperExt  *pubmaticWrapperExt
    88  		expectedPublisherId string
    89  		wantErr             bool
    90  		expectedBidfloor    float64
    91  	}{
    92  		{
    93  			name: "imp.bidfloor empty and kadfloor set",
    94  			args: args{
    95  				imp: &openrtb2.Imp{
    96  					Video: &openrtb2.Video{},
    97  					Ext:   json.RawMessage(`{"bidder":{"kadfloor":"0.12"}}`),
    98  				},
    99  			},
   100  			expectedBidfloor: 0.12,
   101  		},
   102  		{
   103  			name: "imp.bidfloor set and kadfloor empty",
   104  			args: args{
   105  				imp: &openrtb2.Imp{
   106  					BidFloor: 0.12,
   107  					Video:    &openrtb2.Video{},
   108  					Ext:      json.RawMessage(`{"bidder":{}}`),
   109  				},
   110  			},
   111  			expectedBidfloor: 0.12,
   112  		},
   113  		{
   114  			name: "imp.bidfloor set and kadfloor invalid",
   115  			args: args{
   116  				imp: &openrtb2.Imp{
   117  					BidFloor: 0.12,
   118  					Video:    &openrtb2.Video{},
   119  					Ext:      json.RawMessage(`{"bidder":{"kadfloor":"aaa"}}`),
   120  				},
   121  			},
   122  			expectedBidfloor: 0.12,
   123  		},
   124  		{
   125  			name: "imp.bidfloor set and kadfloor set, higher imp.bidfloor",
   126  			args: args{
   127  				imp: &openrtb2.Imp{
   128  					BidFloor: 0.12,
   129  					Video:    &openrtb2.Video{},
   130  					Ext:      json.RawMessage(`{"bidder":{"kadfloor":"0.11"}}`),
   131  				},
   132  			},
   133  			expectedBidfloor: 0.12,
   134  		},
   135  		{
   136  			name: "imp.bidfloor set and kadfloor set, higher kadfloor",
   137  			args: args{
   138  				imp: &openrtb2.Imp{
   139  					BidFloor: 0.12,
   140  					Video:    &openrtb2.Video{},
   141  					Ext:      json.RawMessage(`{"bidder":{"kadfloor":"0.13"}}`),
   142  				},
   143  			},
   144  			expectedBidfloor: 0.13,
   145  		},
   146  		{
   147  			name: "kadfloor string set with whitespace",
   148  			args: args{
   149  				imp: &openrtb2.Imp{
   150  					BidFloor: 0.12,
   151  					Video:    &openrtb2.Video{},
   152  					Ext:      json.RawMessage(`{"bidder":{"kadfloor":" \t  0.13  "}}`),
   153  				},
   154  			},
   155  			expectedBidfloor: 0.13,
   156  		},
   157  	}
   158  	for _, tt := range tests {
   159  		t.Run(tt.name, func(t *testing.T) {
   160  			receivedWrapperExt, receivedPublisherId, err := parseImpressionObject(tt.args.imp, tt.args.extractWrapperExtFromImp, tt.args.extractPubIDFromImp)
   161  			assert.Equal(t, tt.wantErr, err != nil)
   162  			assert.Equal(t, tt.expectedWrapperExt, receivedWrapperExt)
   163  			assert.Equal(t, tt.expectedPublisherId, receivedPublisherId)
   164  			assert.Equal(t, tt.expectedBidfloor, tt.args.imp.BidFloor)
   165  		})
   166  	}
   167  }
   168  
   169  func TestExtractPubmaticExtFromRequest(t *testing.T) {
   170  	type args struct {
   171  		request *openrtb2.BidRequest
   172  	}
   173  	tests := []struct {
   174  		name           string
   175  		args           args
   176  		expectedReqExt extRequestAdServer
   177  		wantErr        bool
   178  	}{
   179  		{
   180  			name: "nil request",
   181  			args: args{
   182  				request: nil,
   183  			},
   184  			wantErr: false,
   185  		},
   186  		{
   187  			name: "nil req.ext",
   188  			args: args{
   189  				request: &openrtb2.BidRequest{Ext: nil},
   190  			},
   191  			wantErr: false,
   192  		},
   193  		{
   194  			name: "Pubmatic wrapper ext missing/empty (empty bidderparms)",
   195  			args: args{
   196  				request: &openrtb2.BidRequest{
   197  					Ext: json.RawMessage(`{"prebid":{"bidderparams":{}}}`),
   198  				},
   199  			},
   200  			expectedReqExt: extRequestAdServer{
   201  				ExtRequest: openrtb_ext.ExtRequest{
   202  					Prebid: openrtb_ext.ExtRequestPrebid{
   203  						BidderParams: json.RawMessage("{}"),
   204  					},
   205  				},
   206  			},
   207  			wantErr: false,
   208  		},
   209  		{
   210  			name: "Only Pubmatic wrapper ext present",
   211  			args: args{
   212  				request: &openrtb2.BidRequest{
   213  					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":{"profile":123,"version":456}}}}`),
   214  				},
   215  			},
   216  			expectedReqExt: extRequestAdServer{
   217  				Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
   218  				ExtRequest: openrtb_ext.ExtRequest{
   219  					Prebid: openrtb_ext.ExtRequestPrebid{
   220  						BidderParams: json.RawMessage(`{"wrapper":{"profile":123,"version":456}}`),
   221  					},
   222  				},
   223  			},
   224  			wantErr: false,
   225  		},
   226  		{
   227  			name: "Invalid Pubmatic wrapper ext",
   228  			args: args{
   229  				request: &openrtb2.BidRequest{
   230  					Ext: json.RawMessage(`{"prebid":{"bidderparams":"}}}`),
   231  				},
   232  			},
   233  			wantErr: true,
   234  		},
   235  		{
   236  			name: "Valid Pubmatic acat ext",
   237  			args: args{
   238  				request: &openrtb2.BidRequest{
   239  					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"acat":[" drg \t","dlu","ssr"],"wrapper":{"profile":123,"version":456}}}}`),
   240  				},
   241  			},
   242  			expectedReqExt: extRequestAdServer{
   243  				Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
   244  				Acat:    []string{"drg", "dlu", "ssr"},
   245  				ExtRequest: openrtb_ext.ExtRequest{
   246  					Prebid: openrtb_ext.ExtRequestPrebid{
   247  						BidderParams: json.RawMessage(`{"acat":[" drg \t","dlu","ssr"],"wrapper":{"profile":123,"version":456}}`),
   248  					},
   249  				},
   250  			},
   251  			wantErr: false,
   252  		},
   253  		{
   254  			name: "Invalid Pubmatic acat ext",
   255  			args: args{
   256  				request: &openrtb2.BidRequest{
   257  					Ext: json.RawMessage(`{"prebid":{"bidderparams":{"acat":[1,3,4],"wrapper":{"profile":123,"version":456}}}}`),
   258  				},
   259  			},
   260  			expectedReqExt: extRequestAdServer{
   261  				Wrapper: &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
   262  				ExtRequest: openrtb_ext.ExtRequest{
   263  					Prebid: openrtb_ext.ExtRequestPrebid{
   264  						BidderParams: json.RawMessage(`{"acat":[1,3,4],"wrapper":{"profile":123,"version":456}}`),
   265  					},
   266  				},
   267  			},
   268  			wantErr: true,
   269  		},
   270  		{
   271  			name: "Valid Pubmatic marketplace ext",
   272  			args: args{
   273  				request: &openrtb2.BidRequest{
   274  					Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":true,"bidders":{"pubmatic":{"enabled":true,"allowedbiddercodes":["groupm"]}}},"bidderparams":{"wrapper":{"profile":123,"version":456}}}}`),
   275  				},
   276  			},
   277  			expectedReqExt: extRequestAdServer{
   278  				Marketplace: &marketplaceReqExt{AllowedBidders: []string{"pubmatic", "groupm"}},
   279  				Wrapper:     &pubmaticWrapperExt{ProfileID: 123, VersionID: 456},
   280  				ExtRequest: openrtb_ext.ExtRequest{
   281  					Prebid: openrtb_ext.ExtRequestPrebid{
   282  						BidderParams:         json.RawMessage(`{"wrapper":{"profile":123,"version":456}}`),
   283  						AlternateBidderCodes: &openrtb_ext.ExtAlternateBidderCodes{Enabled: true, Bidders: map[string]openrtb_ext.ExtAdapterAlternateBidderCodes{"pubmatic": {Enabled: true, AllowedBidderCodes: []string{"groupm"}}}},
   284  					},
   285  				},
   286  			},
   287  			wantErr: false,
   288  		},
   289  	}
   290  	for _, tt := range tests {
   291  		t.Run(tt.name, func(t *testing.T) {
   292  			gotReqExt, err := extractPubmaticExtFromRequest(tt.args.request)
   293  			assert.Equal(t, tt.wantErr, err != nil)
   294  			assert.Equal(t, tt.expectedReqExt, gotReqExt)
   295  		})
   296  	}
   297  }
   298  
   299  func TestPubmaticAdapter_MakeRequests(t *testing.T) {
   300  	type fields struct {
   301  		URI string
   302  	}
   303  	type args struct {
   304  		request *openrtb2.BidRequest
   305  		reqInfo *adapters.ExtraRequestInfo
   306  	}
   307  	tests := []struct {
   308  		name            string
   309  		fields          fields
   310  		args            args
   311  		expectedReqData []*adapters.RequestData
   312  		wantErr         bool
   313  	}{
   314  		// Happy paths covered by TestJsonSamples()
   315  		// Covering only error scenarios here
   316  		{
   317  			name: "invalid bidderparams",
   318  			args: args{
   319  				request: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":"123"}}}`)},
   320  			},
   321  			wantErr: true,
   322  		},
   323  	}
   324  	for _, tt := range tests {
   325  		t.Run(tt.name, func(t *testing.T) {
   326  			a := &PubmaticAdapter{
   327  				URI: tt.fields.URI,
   328  			}
   329  			gotReqData, gotErr := a.MakeRequests(tt.args.request, tt.args.reqInfo)
   330  			assert.Equal(t, tt.wantErr, len(gotErr) != 0)
   331  			assert.Equal(t, tt.expectedReqData, gotReqData)
   332  		})
   333  	}
   334  }
   335  
   336  func TestPubmaticAdapter_MakeBids(t *testing.T) {
   337  	type fields struct {
   338  		URI string
   339  	}
   340  	type args struct {
   341  		internalRequest *openrtb2.BidRequest
   342  		externalRequest *adapters.RequestData
   343  		response        *adapters.ResponseData
   344  	}
   345  	tests := []struct {
   346  		name     string
   347  		fields   fields
   348  		args     args
   349  		wantErr  []error
   350  		wantResp *adapters.BidderResponse
   351  	}{
   352  		{
   353  			name: "happy path, valid response with all bid params",
   354  			args: args{
   355  				response: &adapters.ResponseData{
   356  					StatusCode: http.StatusOK,
   357  					Body:       []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`),
   358  				},
   359  			},
   360  			wantErr: nil,
   361  			wantResp: &adapters.BidderResponse{
   362  				Bids: []*adapters.TypedBid{
   363  					{
   364  						Bid: &openrtb2.Bid{
   365  							ID:      "7706636740145184841",
   366  							ImpID:   "test-imp-id",
   367  							Price:   0.500000,
   368  							AdID:    "29681110",
   369  							AdM:     "some-test-ad",
   370  							ADomain: []string{"pubmatic.com"},
   371  							CrID:    "29681110",
   372  							H:       250,
   373  							W:       300,
   374  							DealID:  "testdeal",
   375  							Ext:     json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}`),
   376  						},
   377  						DealPriority: 1,
   378  						BidType:      openrtb_ext.BidTypeBanner,
   379  						BidVideo:     &openrtb_ext.ExtBidPrebidVideo{},
   380  					},
   381  				},
   382  				Currency: "USD",
   383  			},
   384  		},
   385  		{
   386  			name: "ignore invalid prebiddealpriority",
   387  			args: args{
   388  				response: &adapters.ResponseData{
   389  					StatusCode: http.StatusOK,
   390  					Body:       []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`),
   391  				},
   392  			},
   393  			wantErr: nil,
   394  			wantResp: &adapters.BidderResponse{
   395  				Bids: []*adapters.TypedBid{
   396  					{
   397  						Bid: &openrtb2.Bid{
   398  							ID:      "7706636740145184841",
   399  							ImpID:   "test-imp-id",
   400  							Price:   0.500000,
   401  							AdID:    "29681110",
   402  							AdM:     "some-test-ad",
   403  							ADomain: []string{"pubmatic.com"},
   404  							CrID:    "29681110",
   405  							H:       250,
   406  							W:       300,
   407  							DealID:  "testdeal",
   408  							Ext:     json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}`),
   409  						},
   410  						BidType:  openrtb_ext.BidTypeBanner,
   411  						BidVideo: &openrtb_ext.ExtBidPrebidVideo{},
   412  					},
   413  				},
   414  				Currency: "USD",
   415  			},
   416  		},
   417  	}
   418  	for _, tt := range tests {
   419  		t.Run(tt.name, func(t *testing.T) {
   420  			a := &PubmaticAdapter{
   421  				URI: tt.fields.URI,
   422  			}
   423  			gotResp, gotErr := a.MakeBids(tt.args.internalRequest, tt.args.externalRequest, tt.args.response)
   424  			assert.Equal(t, tt.wantErr, gotErr, gotErr)
   425  			assert.Equal(t, tt.wantResp, gotResp)
   426  		})
   427  	}
   428  }
   429  
   430  func Test_getAlternateBidderCodesFromRequest(t *testing.T) {
   431  	type args struct {
   432  		bidRequest *openrtb2.BidRequest
   433  	}
   434  	tests := []struct {
   435  		name string
   436  		args args
   437  		want []string
   438  	}{
   439  		{
   440  			name: "request.ext nil",
   441  			args: args{
   442  				bidRequest: &openrtb2.BidRequest{Ext: nil},
   443  			},
   444  			want: nil,
   445  		},
   446  		{
   447  			name: "alternatebiddercodes not present in request.ext",
   448  			args: args{
   449  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{}}`)},
   450  			},
   451  			want: nil,
   452  		},
   453  		{
   454  			name: "alternatebiddercodes feature disabled",
   455  			args: args{
   456  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":false,"bidders":{"pubmatic":{"enabled":true,"allowedbiddercodes":["groupm"]}}}}}`)},
   457  			},
   458  			want: []string{"pubmatic"},
   459  		},
   460  		{
   461  			name: "alternatebiddercodes disabled at bidder level",
   462  			args: args{
   463  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":true,"bidders":{"pubmatic":{"enabled":false,"allowedbiddercodes":["groupm"]}}}}}`)},
   464  			},
   465  			want: []string{"pubmatic"},
   466  		},
   467  		{
   468  			name: "alternatebiddercodes list not defined",
   469  			args: args{
   470  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":true,"bidders":{"pubmatic":{"enabled":true}}}}}`)},
   471  			},
   472  			want: []string{"all"},
   473  		},
   474  		{
   475  			name: "wildcard in alternatebiddercodes list",
   476  			args: args{
   477  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":true,"bidders":{"pubmatic":{"enabled":true,"allowedbiddercodes":["*"]}}}}}`)},
   478  			},
   479  			want: []string{"all"},
   480  		},
   481  		{
   482  			name: "empty alternatebiddercodes list",
   483  			args: args{
   484  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":true,"bidders":{"pubmatic":{"enabled":true,"allowedbiddercodes":[]}}}}}`)},
   485  			},
   486  			want: []string{"pubmatic"},
   487  		},
   488  		{
   489  			name: "only groupm in alternatebiddercodes allowed",
   490  			args: args{
   491  				bidRequest: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"alternatebiddercodes":{"enabled":true,"bidders":{"pubmatic":{"enabled":true,"allowedbiddercodes":["groupm"]}}}}}`)},
   492  			},
   493  			want: []string{"pubmatic", "groupm"},
   494  		},
   495  	}
   496  	for _, tt := range tests {
   497  		t.Run(tt.name, func(t *testing.T) {
   498  			var reqExt *openrtb_ext.ExtRequest
   499  			if len(tt.args.bidRequest.Ext) > 0 {
   500  				err := json.Unmarshal(tt.args.bidRequest.Ext, &reqExt)
   501  				if err != nil {
   502  					t.Errorf("getAlternateBidderCodesFromRequest() = %v", err)
   503  				}
   504  			}
   505  
   506  			got := getAlternateBidderCodesFromRequestExt(reqExt)
   507  			assert.ElementsMatch(t, got, tt.want, tt.name)
   508  		})
   509  	}
   510  }
   511  
   512  func TestPopulateFirstPartyDataImpAttributes(t *testing.T) {
   513  	type args struct {
   514  		data      json.RawMessage
   515  		impExtMap map[string]interface{}
   516  	}
   517  	tests := []struct {
   518  		name           string
   519  		args           args
   520  		expectedImpExt map[string]interface{}
   521  	}{
   522  		{
   523  			name: "Only Targeting present in imp.ext.data",
   524  			args: args{
   525  				data:      json.RawMessage(`{"sport":["rugby","cricket"]}`),
   526  				impExtMap: map[string]interface{}{},
   527  			},
   528  			expectedImpExt: map[string]interface{}{
   529  				"key_val": "sport=rugby,cricket",
   530  			},
   531  		},
   532  		{
   533  			name: "Targeting and adserver object present in imp.ext.data",
   534  			args: args{
   535  				data:      json.RawMessage(`{"adserver": {"name": "gam","adslot": "/1111/home"},"pbadslot": "/2222/home","sport":["rugby","cricket"]}`),
   536  				impExtMap: map[string]interface{}{},
   537  			},
   538  			expectedImpExt: map[string]interface{}{
   539  				"dfp_ad_unit_code": "/1111/home",
   540  				"key_val":          "sport=rugby,cricket",
   541  			},
   542  		},
   543  		{
   544  			name: "Targeting and pbadslot key present in imp.ext.data ",
   545  			args: args{
   546  				data:      json.RawMessage(`{"pbadslot": "/2222/home","sport":["rugby","cricket"]}`),
   547  				impExtMap: map[string]interface{}{},
   548  			},
   549  			expectedImpExt: map[string]interface{}{
   550  				"dfp_ad_unit_code": "/2222/home",
   551  				"key_val":          "sport=rugby,cricket",
   552  			},
   553  		},
   554  		{
   555  			name: "Targeting and Invalid Adserver object in imp.ext.data",
   556  			args: args{
   557  				data:      json.RawMessage(`{"adserver": "invalid","sport":["rugby","cricket"]}`),
   558  				impExtMap: map[string]interface{}{},
   559  			},
   560  			expectedImpExt: map[string]interface{}{
   561  				"key_val": "sport=rugby,cricket",
   562  			},
   563  		},
   564  		{
   565  			name: "key_val already present in imp.ext.data",
   566  			args: args{
   567  				data: json.RawMessage(`{"sport":["rugby","cricket"]}`),
   568  				impExtMap: map[string]interface{}{
   569  					"key_val": "k1=v1|k2=v2",
   570  				},
   571  			},
   572  			expectedImpExt: map[string]interface{}{
   573  				"key_val": "k1=v1|k2=v2|sport=rugby,cricket",
   574  			},
   575  		},
   576  		{
   577  			name: "int data present in imp.ext.data",
   578  			args: args{
   579  				data:      json.RawMessage(`{"age": 25}`),
   580  				impExtMap: map[string]interface{}{},
   581  			},
   582  			expectedImpExt: map[string]interface{}{
   583  				"key_val": "age=25",
   584  			},
   585  		},
   586  		{
   587  			name: "float data present in imp.ext.data",
   588  			args: args{
   589  				data:      json.RawMessage(`{"floor": 0.15}`),
   590  				impExtMap: map[string]interface{}{},
   591  			},
   592  			expectedImpExt: map[string]interface{}{
   593  				"key_val": "floor=0.15",
   594  			},
   595  		},
   596  		{
   597  			name: "bool data present in imp.ext.data",
   598  			args: args{
   599  				data:      json.RawMessage(`{"k1": true}`),
   600  				impExtMap: map[string]interface{}{},
   601  			},
   602  			expectedImpExt: map[string]interface{}{
   603  				"key_val": "k1=true",
   604  			},
   605  		},
   606  		{
   607  			name: "imp.ext.data is not present",
   608  			args: args{
   609  				data:      nil,
   610  				impExtMap: map[string]interface{}{},
   611  			},
   612  			expectedImpExt: map[string]interface{}{},
   613  		},
   614  		{
   615  			name: "string with spaces present in imp.ext.data",
   616  			args: args{
   617  				data:      json.RawMessage(`{"  category  ": "   cinema  "}`),
   618  				impExtMap: map[string]interface{}{},
   619  			},
   620  			expectedImpExt: map[string]interface{}{
   621  				"key_val": "category=cinema",
   622  			},
   623  		},
   624  		{
   625  			name: "string array with spaces present in imp.ext.data",
   626  			args: args{
   627  				data:      json.RawMessage(`{"  country\t": ["  India", "\tChina  "]}`),
   628  				impExtMap: map[string]interface{}{},
   629  			},
   630  			expectedImpExt: map[string]interface{}{
   631  				"key_val": "country=India,China",
   632  			},
   633  		},
   634  		{
   635  			name: "Invalid data present in imp.ext.data",
   636  			args: args{
   637  				data:      json.RawMessage(`{"country": [1, "India"],"category":"movies"}`),
   638  				impExtMap: map[string]interface{}{},
   639  			},
   640  			expectedImpExt: map[string]interface{}{
   641  				"key_val": "category=movies",
   642  			},
   643  		},
   644  	}
   645  	for _, tt := range tests {
   646  		t.Run(tt.name, func(t *testing.T) {
   647  			populateFirstPartyDataImpAttributes(tt.args.data, tt.args.impExtMap)
   648  			assert.Equal(t, tt.expectedImpExt, tt.args.impExtMap)
   649  		})
   650  	}
   651  }
   652  
   653  func TestPopulateFirstPartyDataImpAttributesForMultipleAttributes(t *testing.T) {
   654  	impExtMap := map[string]interface{}{
   655  		"key_val": "k1=v1|k2=v2",
   656  	}
   657  	data := json.RawMessage(`{"sport":["rugby","cricket"],"pageType":"article","age":30,"floor":1.25}`)
   658  	expectedKeyValArr := []string{"age=30", "floor=1.25", "k1=v1", "k2=v2", "pageType=article", "sport=rugby,cricket"}
   659  
   660  	populateFirstPartyDataImpAttributes(data, impExtMap)
   661  
   662  	//read dctr value and split on "|" for comparison
   663  	actualKeyValArr := strings.Split(impExtMap[dctrKeyName].(string), "|")
   664  	sort.Strings(actualKeyValArr)
   665  	assert.Equal(t, expectedKeyValArr, actualKeyValArr)
   666  }
   667  
   668  func TestGetStringArray(t *testing.T) {
   669  	tests := []struct {
   670  		name   string
   671  		input  []interface{}
   672  		output []string
   673  	}{
   674  		{
   675  			name:   "Valid String Array",
   676  			input:  append(make([]interface{}, 0), "hello", "world"),
   677  			output: []string{"hello", "world"},
   678  		},
   679  		{
   680  			name:   "Invalid String Array",
   681  			input:  append(make([]interface{}, 0), 1, 2),
   682  			output: nil,
   683  		},
   684  	}
   685  	for _, tt := range tests {
   686  		t.Run(tt.name, func(t *testing.T) {
   687  			got := getStringArray(tt.input)
   688  			assert.Equal(t, tt.output, got)
   689  		})
   690  	}
   691  }
   692  
   693  func TestGetMapFromJSON(t *testing.T) {
   694  	tests := []struct {
   695  		name   string
   696  		input  json.RawMessage
   697  		output map[string]interface{}
   698  	}{
   699  		{
   700  			name:  "Valid JSON",
   701  			input: json.RawMessage(`{"buyid":"testBuyId"}`),
   702  			output: map[string]interface{}{
   703  				"buyid": "testBuyId",
   704  			},
   705  		},
   706  		{
   707  			name:   "Invalid JSON",
   708  			input:  json.RawMessage(`{"buyid":}`),
   709  			output: nil,
   710  		},
   711  	}
   712  	for _, tt := range tests {
   713  		t.Run(tt.name, func(t *testing.T) {
   714  			got := getMapFromJSON(tt.input)
   715  			assert.Equal(t, tt.output, got)
   716  		})
   717  	}
   718  }