github.com/prebid/prebid-server/v2@v2.18.0/privacy/scrubber_test.go (about)

     1  package privacy
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  
     7  	"github.com/prebid/openrtb/v20/openrtb2"
     8  	"github.com/prebid/prebid-server/v2/openrtb_ext"
     9  	"github.com/prebid/prebid-server/v2/util/ptrutil"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestScrubDeviceIDs(t *testing.T) {
    14  	testCases := []struct {
    15  		name           string
    16  		deviceIn       *openrtb2.Device
    17  		expectedDevice *openrtb2.Device
    18  	}{
    19  		{
    20  			name:           "all",
    21  			deviceIn:       &openrtb2.Device{DIDMD5: "MD5", DIDSHA1: "SHA1", DPIDMD5: "MD5", DPIDSHA1: "SHA1", IFA: "IFA", MACMD5: "MD5", MACSHA1: "SHA1"},
    22  			expectedDevice: &openrtb2.Device{DIDMD5: "", DIDSHA1: "", DPIDMD5: "", DPIDSHA1: "", IFA: "", MACMD5: "", MACSHA1: ""},
    23  		},
    24  		{
    25  			name:           "nil",
    26  			deviceIn:       nil,
    27  			expectedDevice: nil,
    28  		},
    29  	}
    30  	for _, test := range testCases {
    31  		t.Run(test.name, func(t *testing.T) {
    32  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Device: test.deviceIn}}
    33  			scrubDeviceIDs(brw)
    34  			brw.RebuildRequest()
    35  			assert.Equal(t, test.expectedDevice, brw.Device)
    36  		})
    37  	}
    38  }
    39  
    40  func TestScrubUserIDs(t *testing.T) {
    41  	testCases := []struct {
    42  		name         string
    43  		userIn       *openrtb2.User
    44  		expectedUser *openrtb2.User
    45  	}{
    46  		{
    47  			name:         "all",
    48  			userIn:       &openrtb2.User{Data: []openrtb2.Data{}, ID: "ID", BuyerUID: "bID", Yob: 2000, Gender: "M", Keywords: "keywords", KwArray: nil},
    49  			expectedUser: &openrtb2.User{Data: nil, ID: "", BuyerUID: "", Yob: 0, Gender: "", Keywords: "", KwArray: nil},
    50  		},
    51  		{
    52  			name:         "nil",
    53  			userIn:       nil,
    54  			expectedUser: nil,
    55  		},
    56  	}
    57  	for _, test := range testCases {
    58  		t.Run(test.name, func(t *testing.T) {
    59  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{User: test.userIn}}
    60  			scrubUserIDs(brw)
    61  			brw.RebuildRequest()
    62  			assert.Equal(t, test.expectedUser, brw.User)
    63  		})
    64  	}
    65  }
    66  
    67  func TestScrubUserDemographics(t *testing.T) {
    68  	testCases := []struct {
    69  		name         string
    70  		userIn       *openrtb2.User
    71  		expectedUser *openrtb2.User
    72  	}{
    73  		{
    74  			name:         "all",
    75  			userIn:       &openrtb2.User{ID: "ID", BuyerUID: "bID", Yob: 2000, Gender: "M"},
    76  			expectedUser: &openrtb2.User{ID: "", BuyerUID: "", Yob: 0, Gender: ""},
    77  		},
    78  		{
    79  			name:         "nil",
    80  			userIn:       nil,
    81  			expectedUser: nil,
    82  		},
    83  	}
    84  	for _, test := range testCases {
    85  		t.Run(test.name, func(t *testing.T) {
    86  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{User: test.userIn}}
    87  			scrubUserDemographics(brw)
    88  			brw.RebuildRequest()
    89  			assert.Equal(t, test.expectedUser, brw.User)
    90  		})
    91  	}
    92  }
    93  
    94  func TestScrubUserExt(t *testing.T) {
    95  	testCases := []struct {
    96  		name         string
    97  		userIn       *openrtb2.User
    98  		fieldName    string
    99  		expectedUser *openrtb2.User
   100  	}{
   101  		{
   102  			name:         "nil_user",
   103  			userIn:       nil,
   104  			expectedUser: nil,
   105  		},
   106  		{
   107  			name:         "nil_ext",
   108  			userIn:       &openrtb2.User{ID: "ID", Ext: nil},
   109  			expectedUser: &openrtb2.User{ID: "ID", Ext: nil},
   110  		},
   111  		{
   112  			name:         "empty_ext",
   113  			userIn:       &openrtb2.User{ID: "ID", Ext: json.RawMessage(`{}`)},
   114  			expectedUser: &openrtb2.User{ID: "ID", Ext: json.RawMessage(`{}`)},
   115  		},
   116  		{
   117  			name:         "ext_with_field",
   118  			userIn:       &openrtb2.User{ID: "ID", Ext: json.RawMessage(`{"data":"123","test":1}`)},
   119  			fieldName:    "data",
   120  			expectedUser: &openrtb2.User{ID: "ID", Ext: json.RawMessage(`{"test":1}`)},
   121  		},
   122  		{
   123  			name:         "ext_without_field",
   124  			userIn:       &openrtb2.User{ID: "ID", Ext: json.RawMessage(`{"data":"123","test":1}`)},
   125  			fieldName:    "noData",
   126  			expectedUser: &openrtb2.User{ID: "ID", Ext: json.RawMessage(`{"data":"123","test":1}`)},
   127  		},
   128  		{
   129  			name:         "nil",
   130  			userIn:       nil,
   131  			expectedUser: nil,
   132  		},
   133  	}
   134  	for _, test := range testCases {
   135  		t.Run(test.name, func(t *testing.T) {
   136  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{User: test.userIn}}
   137  			scrubUserExt(brw, test.fieldName)
   138  			brw.RebuildRequest()
   139  			assert.Equal(t, test.expectedUser, brw.User)
   140  		})
   141  	}
   142  }
   143  
   144  func TestScrubEids(t *testing.T) {
   145  	testCases := []struct {
   146  		name         string
   147  		userIn       *openrtb2.User
   148  		expectedUser *openrtb2.User
   149  	}{
   150  		{
   151  			name:         "eids",
   152  			userIn:       &openrtb2.User{ID: "ID", EIDs: []openrtb2.EID{}},
   153  			expectedUser: &openrtb2.User{ID: "ID", EIDs: nil},
   154  		},
   155  		{
   156  			name:         "nil_eids",
   157  			userIn:       &openrtb2.User{ID: "ID", EIDs: nil},
   158  			expectedUser: &openrtb2.User{ID: "ID", EIDs: nil},
   159  		},
   160  		{
   161  			name:         "nil",
   162  			userIn:       nil,
   163  			expectedUser: nil,
   164  		},
   165  	}
   166  	for _, test := range testCases {
   167  		t.Run(test.name, func(t *testing.T) {
   168  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{User: test.userIn}}
   169  			ScrubEIDs(brw)
   170  			brw.RebuildRequest()
   171  			assert.Equal(t, test.expectedUser, brw.User)
   172  		})
   173  	}
   174  }
   175  
   176  func TestScrubTID(t *testing.T) {
   177  	testCases := []struct {
   178  		name           string
   179  		sourceIn       *openrtb2.Source
   180  		impIn          []openrtb2.Imp
   181  		expectedSource *openrtb2.Source
   182  		expectedImp    []openrtb2.Imp
   183  	}{
   184  		{
   185  			name:           "nil",
   186  			sourceIn:       nil,
   187  			expectedSource: nil,
   188  		},
   189  		{
   190  			name:           "nil_imp_ext",
   191  			sourceIn:       &openrtb2.Source{TID: "tid"},
   192  			impIn:          []openrtb2.Imp{{ID: "impID", Ext: nil}},
   193  			expectedSource: &openrtb2.Source{TID: ""},
   194  			expectedImp:    []openrtb2.Imp{{ID: "impID", Ext: nil}},
   195  		},
   196  		{
   197  			name:           "empty_imp_ext",
   198  			sourceIn:       &openrtb2.Source{TID: "tid"},
   199  			impIn:          []openrtb2.Imp{{ID: "impID", Ext: json.RawMessage(`{}`)}},
   200  			expectedSource: &openrtb2.Source{TID: ""},
   201  			expectedImp:    []openrtb2.Imp{{ID: "impID", Ext: json.RawMessage(`{}`)}},
   202  		},
   203  		{
   204  			name:           "ext_with_tid",
   205  			sourceIn:       &openrtb2.Source{TID: "tid"},
   206  			impIn:          []openrtb2.Imp{{ID: "impID", Ext: json.RawMessage(`{"tid":"123","test":1}`)}},
   207  			expectedSource: &openrtb2.Source{TID: ""},
   208  			expectedImp:    []openrtb2.Imp{{ID: "impID", Ext: json.RawMessage(`{"test":1}`)}},
   209  		},
   210  		{
   211  			name:           "ext_without_tid",
   212  			sourceIn:       &openrtb2.Source{TID: "tid"},
   213  			impIn:          []openrtb2.Imp{{ID: "impID", Ext: json.RawMessage(`{"data":"123","test":1}`)}},
   214  			expectedSource: &openrtb2.Source{TID: ""},
   215  			expectedImp:    []openrtb2.Imp{{ID: "impID", Ext: json.RawMessage(`{"data":"123","test":1}`)}},
   216  		},
   217  	}
   218  	for _, test := range testCases {
   219  		t.Run(test.name, func(t *testing.T) {
   220  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Source: test.sourceIn, Imp: test.impIn}}
   221  			ScrubTID(brw)
   222  			brw.RebuildRequest()
   223  			assert.Equal(t, test.expectedSource, brw.Source)
   224  			assert.Equal(t, test.expectedImp, brw.Imp)
   225  		})
   226  	}
   227  }
   228  
   229  func TestScrubGEO(t *testing.T) {
   230  	testCases := []struct {
   231  		name           string
   232  		userIn         *openrtb2.User
   233  		expectedUser   *openrtb2.User
   234  		deviceIn       *openrtb2.Device
   235  		expectedDevice *openrtb2.Device
   236  	}{
   237  		{
   238  			name:           "nil",
   239  			userIn:         nil,
   240  			expectedUser:   nil,
   241  			deviceIn:       nil,
   242  			expectedDevice: nil,
   243  		},
   244  		{
   245  			name:           "nil_user_geo",
   246  			userIn:         &openrtb2.User{ID: "ID", Geo: nil},
   247  			expectedUser:   &openrtb2.User{ID: "ID", Geo: nil},
   248  			deviceIn:       &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   249  			expectedDevice: &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.12)}},
   250  		},
   251  		{
   252  			name:           "with_user_geo",
   253  			userIn:         &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   254  			expectedUser:   &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.12)}},
   255  			deviceIn:       &openrtb2.Device{},
   256  			expectedDevice: &openrtb2.Device{},
   257  		},
   258  		{
   259  			name:           "nil_device_geo",
   260  			userIn:         &openrtb2.User{},
   261  			expectedUser:   &openrtb2.User{},
   262  			deviceIn:       &openrtb2.Device{Geo: nil},
   263  			expectedDevice: &openrtb2.Device{Geo: nil},
   264  		},
   265  		{
   266  			name:           "with_device_geo",
   267  			userIn:         &openrtb2.User{},
   268  			expectedUser:   &openrtb2.User{},
   269  			deviceIn:       &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   270  			expectedDevice: &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.12)}},
   271  		},
   272  		{
   273  			name:           "with_user_and_device_geo",
   274  			userIn:         &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   275  			expectedUser:   &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.12)}},
   276  			deviceIn:       &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   277  			expectedDevice: &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.12)}},
   278  		},
   279  	}
   280  	for _, test := range testCases {
   281  		t.Run(test.name, func(t *testing.T) {
   282  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{User: test.userIn, Device: test.deviceIn}}
   283  			scrubGEO(brw)
   284  			brw.RebuildRequest()
   285  			assert.Equal(t, test.expectedUser, brw.User)
   286  			assert.Equal(t, test.expectedDevice, brw.Device)
   287  		})
   288  	}
   289  }
   290  
   291  func TestScrubGeoFull(t *testing.T) {
   292  	testCases := []struct {
   293  		name           string
   294  		userIn         *openrtb2.User
   295  		expectedUser   *openrtb2.User
   296  		deviceIn       *openrtb2.Device
   297  		expectedDevice *openrtb2.Device
   298  	}{
   299  		{
   300  			name:           "nil",
   301  			userIn:         nil,
   302  			expectedUser:   nil,
   303  			deviceIn:       nil,
   304  			expectedDevice: nil,
   305  		},
   306  		{
   307  			name:           "nil_user_geo",
   308  			userIn:         &openrtb2.User{ID: "ID", Geo: nil},
   309  			expectedUser:   &openrtb2.User{ID: "ID", Geo: nil},
   310  			deviceIn:       &openrtb2.Device{},
   311  			expectedDevice: &openrtb2.Device{},
   312  		},
   313  		{
   314  			name:           "with_user_geo",
   315  			userIn:         &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   316  			expectedUser:   &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{}},
   317  			deviceIn:       &openrtb2.Device{},
   318  			expectedDevice: &openrtb2.Device{},
   319  		},
   320  		{
   321  			name:           "nil_device_geo",
   322  			userIn:         &openrtb2.User{},
   323  			expectedUser:   &openrtb2.User{},
   324  			deviceIn:       &openrtb2.Device{Geo: nil},
   325  			expectedDevice: &openrtb2.Device{Geo: nil},
   326  		},
   327  		{
   328  			name:           "with_device_geo",
   329  			userIn:         &openrtb2.User{},
   330  			expectedUser:   &openrtb2.User{},
   331  			deviceIn:       &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   332  			expectedDevice: &openrtb2.Device{Geo: &openrtb2.Geo{}},
   333  		},
   334  		{
   335  			name:           "with_user_and_device_geo",
   336  			userIn:         &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   337  			expectedUser:   &openrtb2.User{ID: "ID", Geo: &openrtb2.Geo{}},
   338  			deviceIn:       &openrtb2.Device{Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(123.123)}},
   339  			expectedDevice: &openrtb2.Device{Geo: &openrtb2.Geo{}},
   340  		},
   341  	}
   342  	for _, test := range testCases {
   343  		t.Run(test.name, func(t *testing.T) {
   344  			brw := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{User: test.userIn, Device: test.deviceIn}}
   345  			scrubGeoFull(brw)
   346  			brw.RebuildRequest()
   347  			assert.Equal(t, test.expectedUser, brw.User)
   348  			assert.Equal(t, test.expectedDevice, brw.Device)
   349  		})
   350  	}
   351  }
   352  
   353  func TestScrubIP(t *testing.T) {
   354  	testCases := []struct {
   355  		IP        string
   356  		cleanedIP string
   357  		bits      int
   358  		maskBits  int
   359  	}{
   360  		{
   361  			IP:        "0:0:0:0:0:0:0:0",
   362  			cleanedIP: "::",
   363  			bits:      128,
   364  			maskBits:  56,
   365  		},
   366  		{
   367  			IP:        "",
   368  			cleanedIP: "",
   369  			bits:      128,
   370  			maskBits:  56,
   371  		},
   372  		{
   373  			IP:        "1111:2222:3333:4444:5555:6666:7777:8888",
   374  			cleanedIP: "1111:2222:3333:4400::",
   375  			bits:      128,
   376  			maskBits:  56,
   377  		},
   378  		{
   379  			IP:        "1111:2222:3333:4444:5555:6666:7777:8888",
   380  			cleanedIP: "1111:2222::",
   381  			bits:      128,
   382  			maskBits:  34,
   383  		},
   384  		{
   385  			IP:        "1111:0:3333:4444:5555:6666:7777:8888",
   386  			cleanedIP: "1111:0:3333:4400::",
   387  			bits:      128,
   388  			maskBits:  56,
   389  		},
   390  		{
   391  			IP:        "1111::6666:7777:8888",
   392  			cleanedIP: "1111::",
   393  			bits:      128,
   394  			maskBits:  56,
   395  		},
   396  		{
   397  			IP:        "2001:1db8:0000:0000:0000:ff00:0042:8329",
   398  			cleanedIP: "2001:1db8::ff00:0:0",
   399  			bits:      128,
   400  			maskBits:  96,
   401  		},
   402  		{
   403  			IP:        "2001:1db8:0000:0000:0000:ff00:0:0",
   404  			cleanedIP: "2001:1db8::ff00:0:0",
   405  			bits:      128,
   406  			maskBits:  96,
   407  		},
   408  	}
   409  	for _, test := range testCases {
   410  		t.Run(test.IP, func(t *testing.T) {
   411  			// bits: ipv6 - 128, ipv4 - 32
   412  			result := scrubIP(test.IP, test.maskBits, test.bits)
   413  			assert.Equal(t, test.cleanedIP, result)
   414  		})
   415  	}
   416  }
   417  
   418  func TestScrubGeoPrecision(t *testing.T) {
   419  	geo := &openrtb2.Geo{
   420  		Lat:   ptrutil.ToPtr(123.456),
   421  		Lon:   ptrutil.ToPtr(678.89),
   422  		Metro: "some metro",
   423  		City:  "some city",
   424  		ZIP:   "some zip",
   425  	}
   426  	geoExpected := &openrtb2.Geo{
   427  		Lat:   ptrutil.ToPtr(123.46),
   428  		Lon:   ptrutil.ToPtr(678.89),
   429  		Metro: "some metro",
   430  		City:  "some city",
   431  		ZIP:   "some zip",
   432  	}
   433  
   434  	result := scrubGeoPrecision(geo)
   435  
   436  	assert.Equal(t, geoExpected, result)
   437  }
   438  
   439  func TestScrubGeoPrecisionWhenNil(t *testing.T) {
   440  	result := scrubGeoPrecision(nil)
   441  	assert.Nil(t, result)
   442  }
   443  
   444  func TestScrubUserExtIDs(t *testing.T) {
   445  	testCases := []struct {
   446  		description string
   447  		userExt     json.RawMessage
   448  		expected    json.RawMessage
   449  	}{
   450  		{
   451  			description: "Nil",
   452  			userExt:     nil,
   453  			expected:    nil,
   454  		},
   455  		{
   456  			description: "Empty String",
   457  			userExt:     json.RawMessage(``),
   458  			expected:    json.RawMessage(``),
   459  		},
   460  		{
   461  			description: "Empty Object",
   462  			userExt:     json.RawMessage(`{}`),
   463  			expected:    json.RawMessage(`{}`),
   464  		},
   465  		{
   466  			description: "Do Nothing When Malformed",
   467  			userExt:     json.RawMessage(`malformed`),
   468  			expected:    json.RawMessage(`malformed`),
   469  		},
   470  		{
   471  			description: "Do Nothing When No IDs Present",
   472  			userExt:     json.RawMessage(`{"anyExisting":42}}`),
   473  			expected:    json.RawMessage(`{"anyExisting":42}}`),
   474  		},
   475  		{
   476  			description: "Remove eids",
   477  			userExt:     json.RawMessage(`{"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
   478  			expected:    json.RawMessage(`{}`),
   479  		},
   480  		{
   481  			description: "Remove eids - With Other Data",
   482  			userExt:     json.RawMessage(`{"anyExisting":42,"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
   483  			expected:    json.RawMessage(`{"anyExisting":42}`),
   484  		},
   485  		{
   486  			description: "Remove eids - With Other Nested Data",
   487  			userExt:     json.RawMessage(`{"anyExisting":{"existing":42},"eids":[{"source":"anySource","id":"anyId","uids":[{"id":"anyId","ext":{"id":42}}],"ext":{"id":42}}]}`),
   488  			expected:    json.RawMessage(`{"anyExisting":{"existing":42}}`),
   489  		},
   490  		{
   491  			description: "Remove eids Only - Empty Array",
   492  			userExt:     json.RawMessage(`{"eids":[]}`),
   493  			expected:    json.RawMessage(`{}`),
   494  		},
   495  	}
   496  
   497  	for _, test := range testCases {
   498  		result := scrubExtIDs(test.userExt, "eids")
   499  		assert.Equal(t, test.expected, result, test.description)
   500  	}
   501  }