github.com/prebid/prebid-server/v2@v2.18.0/adservertargeting/requestlookup_test.go (about)

     1  package adservertargeting
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/url"
     6  	"testing"
     7  
     8  	"github.com/prebid/openrtb/v20/openrtb2"
     9  	"github.com/prebid/prebid-server/v2/openrtb_ext"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestGetAdServerTargeting(t *testing.T) {
    14  
    15  	testCases := []struct {
    16  		description       string
    17  		inputRequestExt   json.RawMessage
    18  		expectedTargeting []openrtb_ext.AdServerTarget
    19  		expectedError     bool
    20  	}{
    21  		{
    22  			description:       "valid request with no ext.prebid",
    23  			inputRequestExt:   json.RawMessage(``),
    24  			expectedTargeting: nil,
    25  			expectedError:     false,
    26  		},
    27  		{
    28  			description:       "valid request with correct ext.prebid, no ad server targeting",
    29  			inputRequestExt:   json.RawMessage(`{"prebid":{}}`),
    30  			expectedTargeting: nil,
    31  			expectedError:     false,
    32  		},
    33  		{
    34  			description:       "valid request with correct ext.prebid, and empty ad server targeting",
    35  			inputRequestExt:   json.RawMessage(`{"prebid":{"adservertargeting":[]}}`),
    36  			expectedTargeting: []openrtb_ext.AdServerTarget{},
    37  			expectedError:     false,
    38  		},
    39  		{
    40  			description: "valid request with correct ext.prebid, and with ad server targeting",
    41  			inputRequestExt: json.RawMessage(`{"prebid":{"adservertargeting":[
    42  					{"key": "adt_key",
    43                      "source": "bidrequest",
    44                      "value": "ext.prebid.data"}
    45  				]}}`),
    46  			expectedTargeting: []openrtb_ext.AdServerTarget{
    47  				{Key: "adt_key", Source: "bidrequest", Value: "ext.prebid.data"},
    48  			},
    49  			expectedError: false,
    50  		},
    51  	}
    52  
    53  	for _, test := range testCases {
    54  		request := &openrtb_ext.RequestWrapper{
    55  			BidRequest: &openrtb2.BidRequest{ID: "req_id", Ext: test.inputRequestExt},
    56  		}
    57  
    58  		actualTargeting, err := getAdServerTargeting(request)
    59  
    60  		assert.Equal(t, test.expectedTargeting, actualTargeting, "targeting data doesn't match")
    61  		if test.expectedError {
    62  			assert.Error(t, err, "expected error not returned")
    63  		} else {
    64  			assert.NoError(t, err, "unexpected error returned")
    65  		}
    66  	}
    67  }
    68  
    69  func TestValidateAdServerTargeting(t *testing.T) {
    70  	testCases := []struct {
    71  		description       string
    72  		inputTargeting    []openrtb_ext.AdServerTarget
    73  		expectedTargeting []openrtb_ext.AdServerTarget
    74  		expectedWarnings  []openrtb_ext.ExtBidderMessage
    75  	}{
    76  		{
    77  			description: "valid targeting object",
    78  			inputTargeting: []openrtb_ext.AdServerTarget{
    79  				{Key: "adt_key", Source: "bidrequest", Value: "ext.prebid.data"},
    80  			},
    81  			expectedTargeting: []openrtb_ext.AdServerTarget{
    82  				{Key: "adt_key", Source: "bidrequest", Value: "ext.prebid.data"},
    83  			},
    84  			expectedWarnings: []openrtb_ext.ExtBidderMessage(nil),
    85  		},
    86  		{
    87  			description: "invalid targeting object: key",
    88  			inputTargeting: []openrtb_ext.AdServerTarget{
    89  				{Key: "", Source: "bidrequest", Value: "ext.prebid.data"},
    90  			},
    91  			expectedTargeting: []openrtb_ext.AdServerTarget(nil),
    92  			expectedWarnings: []openrtb_ext.ExtBidderMessage{
    93  				{Code: 10007, Message: "Key is empty for the ad server targeting object at index 0"},
    94  			},
    95  		},
    96  		{
    97  			description: "invalid targeting object: source",
    98  			inputTargeting: []openrtb_ext.AdServerTarget{
    99  				{Key: "adt_key", Source: "incorrect", Value: "ext.prebid.data"},
   100  			},
   101  			expectedTargeting: []openrtb_ext.AdServerTarget(nil),
   102  			expectedWarnings: []openrtb_ext.ExtBidderMessage{
   103  				{Code: 10007, Message: "Incorrect source for the ad server targeting object at index 0"},
   104  			},
   105  		},
   106  		{
   107  			description: "invalid targeting object: value",
   108  			inputTargeting: []openrtb_ext.AdServerTarget{
   109  				{Key: "adt_key", Source: "static", Value: ""},
   110  			},
   111  			expectedTargeting: []openrtb_ext.AdServerTarget(nil),
   112  			expectedWarnings: []openrtb_ext.ExtBidderMessage{
   113  				{Code: 10007, Message: "Value is empty for the ad server targeting object at index 0"},
   114  			},
   115  		},
   116  		{
   117  			description: "valid and invalid targeting object",
   118  			inputTargeting: []openrtb_ext.AdServerTarget{
   119  				{Key: "adt_key1", Source: "static", Value: "valid"},
   120  				{Key: "adt_key2", Source: "static", Value: ""},
   121  			},
   122  			expectedTargeting: []openrtb_ext.AdServerTarget{
   123  				{Key: "adt_key1", Source: "static", Value: "valid"},
   124  			},
   125  			expectedWarnings: []openrtb_ext.ExtBidderMessage{
   126  				{Code: 10007, Message: "Value is empty for the ad server targeting object at index 1"},
   127  			},
   128  		},
   129  	}
   130  
   131  	for _, test := range testCases {
   132  		actualTargeting, actualWarnings := validateAdServerTargeting(test.inputTargeting)
   133  		assert.Equal(t, test.expectedTargeting, actualTargeting, "incorrect targeting data")
   134  		assert.Equal(t, test.expectedWarnings, actualWarnings, "incorrect warnings")
   135  	}
   136  }
   137  
   138  func TestGetValueFromBidRequest(t *testing.T) {
   139  
   140  	testCases := []struct {
   141  		description       string
   142  		inputPath         string
   143  		expectedTargeting RequestTargetingData
   144  		expectedError     bool
   145  	}{
   146  		{
   147  			description:       "get existing value from query params",
   148  			inputPath:         "ext.prebid.amp.data.amp-key",
   149  			expectedTargeting: RequestTargetingData{SingleVal: json.RawMessage(`testAmpKey`)},
   150  			expectedError:     false,
   151  		},
   152  		{
   153  			description:       "get non-existing value from query params",
   154  			inputPath:         "ext.prebid.amp.data.amp-key-not-existing",
   155  			expectedTargeting: RequestTargetingData{},
   156  			expectedError:     true,
   157  		},
   158  		{
   159  			description: "get existing value from impressions",
   160  			inputPath:   "imp.banner.h",
   161  			expectedTargeting: RequestTargetingData{
   162  				TargetingValueByImpId: map[string][]byte{
   163  					"test_imp1": []byte(`350`),
   164  					"test_imp2": []byte(`360`),
   165  				},
   166  			},
   167  			expectedError: false,
   168  		},
   169  		{
   170  			description: "get existing value from impressions ext",
   171  			inputPath:   "imp.ext.appnexus.placementId",
   172  			expectedTargeting: RequestTargetingData{
   173  				TargetingValueByImpId: map[string][]byte{
   174  					"test_imp1": []byte(`123`),
   175  					"test_imp2": []byte(`456`),
   176  				},
   177  			},
   178  			expectedError: false,
   179  		},
   180  		{
   181  			description:       "get non-existing value from impressions",
   182  			inputPath:         "imp.video",
   183  			expectedTargeting: RequestTargetingData{},
   184  			expectedError:     true,
   185  		},
   186  		{
   187  			description: "get existing value from req",
   188  			inputPath:   "site.page",
   189  			expectedTargeting: RequestTargetingData{
   190  				SingleVal: json.RawMessage(`test.com`),
   191  			},
   192  			expectedError: false,
   193  		},
   194  		{
   195  			description:       "get non-existing value from req",
   196  			inputPath:         "app",
   197  			expectedTargeting: RequestTargetingData{},
   198  			expectedError:     true,
   199  		},
   200  	}
   201  
   202  	reqCache := requestCache{
   203  		resolvedReq: json.RawMessage(reqFullValid),
   204  	}
   205  
   206  	u, _ := url.Parse(testUrl)
   207  	params := u.Query()
   208  
   209  	for _, test := range testCases {
   210  		resTargetingData, err := getValueFromBidRequest(&reqCache, test.inputPath, params)
   211  
   212  		assert.Equal(t, test.expectedTargeting, resTargetingData, "incorrect targeting data returned")
   213  
   214  		if test.expectedError {
   215  			assert.Error(t, err, "expected error not returned")
   216  		} else {
   217  			assert.NoError(t, err, "unexpected error returned")
   218  		}
   219  	}
   220  }
   221  
   222  func TestGetValueFromQueryParam(t *testing.T) {
   223  	u, _ := url.Parse(testUrl)
   224  	params := u.Query()
   225  
   226  	testCases := []struct {
   227  		description   string
   228  		inputPath     string
   229  		expectedValue json.RawMessage
   230  		expectedError bool
   231  	}{
   232  		{
   233  			description:   "get existing value from query params",
   234  			inputPath:     "ext.prebid.amp.data.amp-key",
   235  			expectedValue: json.RawMessage(`testAmpKey`),
   236  			expectedError: false,
   237  		},
   238  		{
   239  			description:   "get non-existing value from query params",
   240  			inputPath:     "ext.prebid.amp.data.amp-key-not-existing",
   241  			expectedValue: nil,
   242  			expectedError: true,
   243  		},
   244  		{
   245  			description:   "get value from not query params path",
   246  			inputPath:     "ext.data.amp-key-not-existing",
   247  			expectedValue: nil,
   248  			expectedError: false,
   249  		},
   250  	}
   251  
   252  	for _, test := range testCases {
   253  		res, err := getValueFromQueryParam(test.inputPath, params)
   254  
   255  		assert.Equal(t, test.expectedValue, res, "incorrect value found")
   256  		if test.expectedError {
   257  			assert.Error(t, err, "expected error not returned")
   258  		} else {
   259  			assert.NoError(t, err, "unexpected error returned")
   260  		}
   261  	}
   262  }
   263  
   264  func TestGetValueFromImp(t *testing.T) {
   265  
   266  	testCases := []struct {
   267  		description       string
   268  		inputPath         string
   269  		inputRequest      json.RawMessage
   270  		expectedTargeting map[string][]byte
   271  		expectedError     bool
   272  	}{
   273  
   274  		{
   275  			description:  "get existing value from impressions",
   276  			inputPath:    "imp.banner.h",
   277  			inputRequest: json.RawMessage(reqFullValid),
   278  			expectedTargeting: map[string][]byte{
   279  				"test_imp1": []byte(`350`),
   280  				"test_imp2": []byte(`360`),
   281  			},
   282  			expectedError: false,
   283  		},
   284  		{
   285  			description: "get existing value from impressions ext",
   286  			inputPath:   "imp.ext.appnexus.placementId",
   287  			expectedTargeting: map[string][]byte{
   288  				"test_imp1": []byte(`123`),
   289  				"test_imp2": []byte(`456`),
   290  			},
   291  			inputRequest:  json.RawMessage(reqFullValid),
   292  			expectedError: false,
   293  		},
   294  		{
   295  			description:       "get non-existing value from impressions",
   296  			inputPath:         "imp.video",
   297  			expectedTargeting: map[string][]byte(nil),
   298  			inputRequest:      json.RawMessage(reqFullValid),
   299  			expectedError:     true,
   300  		},
   301  		{
   302  			description:       "get value from invalid impressions",
   303  			inputPath:         "imp.video",
   304  			expectedTargeting: map[string][]byte(nil),
   305  			inputRequest:      json.RawMessage(reqFullInvalid),
   306  			expectedError:     true,
   307  		},
   308  		{
   309  			description:       "get value from request without impressions",
   310  			inputPath:         "imp.video",
   311  			expectedTargeting: map[string][]byte(nil),
   312  			inputRequest:      json.RawMessage(`{}`),
   313  			expectedError:     true,
   314  		},
   315  	}
   316  
   317  	for _, test := range testCases {
   318  
   319  		reqCache := requestCache{
   320  			resolvedReq: test.inputRequest,
   321  		}
   322  
   323  		resData, err := getValueFromImp(test.inputPath, &reqCache)
   324  
   325  		assert.Equal(t, test.expectedTargeting, resData, "incorrect imp data returned")
   326  
   327  		if test.expectedError {
   328  			assert.Error(t, err, "expected error not returned")
   329  		} else {
   330  			assert.NoError(t, err, "unexpected error returned")
   331  		}
   332  	}
   333  }
   334  
   335  func TestGetValueFromRequestJson(t *testing.T) {
   336  
   337  	testCases := []struct {
   338  		description   string
   339  		inputPath     string
   340  		expectedValue json.RawMessage
   341  		expectedError bool
   342  	}{
   343  
   344  		{
   345  			description:   "get existing value from req",
   346  			inputPath:     "site.page",
   347  			expectedValue: json.RawMessage(`test.com`),
   348  			expectedError: false,
   349  		},
   350  		{
   351  			description:   "get non-existing value from req",
   352  			inputPath:     "app",
   353  			expectedValue: json.RawMessage(nil),
   354  			expectedError: true,
   355  		},
   356  	}
   357  
   358  	reqCache := requestCache{
   359  		resolvedReq: json.RawMessage(reqFullValid),
   360  	}
   361  
   362  	for _, test := range testCases {
   363  		resValue, err := getDataFromRequestJson(test.inputPath, &reqCache)
   364  
   365  		assert.Equal(t, test.expectedValue, resValue, "incorrect request data returned")
   366  
   367  		if test.expectedError {
   368  			assert.Error(t, err, "expected error not returned")
   369  		} else {
   370  			assert.NoError(t, err, "unexpected error returned")
   371  		}
   372  	}
   373  }