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

     1  package ccpa
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  )
     8  
     9  func TestValidateConsent(t *testing.T) {
    10  	testCases := []struct {
    11  		description string
    12  		consent     string
    13  		expected    bool
    14  	}{
    15  		{
    16  			description: "Empty String",
    17  			consent:     "",
    18  			expected:    true,
    19  		},
    20  		{
    21  			description: "Valid Consent With Opt Out",
    22  			consent:     "1NYN",
    23  			expected:    true,
    24  		},
    25  		{
    26  			description: "Valid Consent Without Opt Out",
    27  			consent:     "1NNN",
    28  			expected:    true,
    29  		},
    30  		{
    31  			description: "Invalid",
    32  			consent:     "malformed",
    33  			expected:    false,
    34  		},
    35  	}
    36  
    37  	for _, test := range testCases {
    38  		result := ValidateConsent(test.consent)
    39  		assert.Equal(t, test.expected, result, test.description)
    40  	}
    41  }
    42  
    43  func TestParse(t *testing.T) {
    44  	validBidders := map[string]struct{}{"a": {}}
    45  
    46  	testCases := []struct {
    47  		description    string
    48  		consent        string
    49  		noSaleBidders  []string
    50  		expectedPolicy ParsedPolicy
    51  		expectedError  string
    52  	}{
    53  		{
    54  			description:    "Consent Error",
    55  			consent:        "malformed",
    56  			noSaleBidders:  []string{},
    57  			expectedPolicy: ParsedPolicy{},
    58  			expectedError:  "request.regs.ext.us_privacy must contain 4 characters",
    59  		},
    60  		{
    61  			description:    "No Sale Error",
    62  			consent:        "1NYN",
    63  			noSaleBidders:  []string{"b"},
    64  			expectedPolicy: ParsedPolicy{},
    65  			expectedError:  "request.ext.prebid.nosale is invalid: unrecognized bidder 'b'",
    66  		},
    67  		{
    68  			description:   "Success",
    69  			consent:       "1NYN",
    70  			noSaleBidders: []string{"a"},
    71  			expectedPolicy: ParsedPolicy{
    72  				consentSpecified:      true,
    73  				consentOptOutSale:     true,
    74  				noSaleForAllBidders:   false,
    75  				noSaleSpecificBidders: map[string]struct{}{"a": {}},
    76  			},
    77  		},
    78  	}
    79  
    80  	for _, test := range testCases {
    81  		policy := Policy{test.consent, test.noSaleBidders}
    82  
    83  		result, err := policy.Parse(validBidders)
    84  
    85  		if test.expectedError == "" {
    86  			assert.NoError(t, err, test.description)
    87  		} else {
    88  			assert.EqualError(t, err, test.expectedError, test.description)
    89  		}
    90  
    91  		assert.Equal(t, test.expectedPolicy, result, test.description)
    92  	}
    93  }
    94  
    95  func TestParseConsent(t *testing.T) {
    96  	testCases := []struct {
    97  		description    string
    98  		consent        string
    99  		expectedResult bool
   100  		expectedError  string
   101  	}{
   102  		{
   103  			description:    "Valid",
   104  			consent:        "1NYN",
   105  			expectedResult: true,
   106  		},
   107  		{
   108  			description:    "Valid - Not Sale",
   109  			consent:        "1NNN",
   110  			expectedResult: false,
   111  		},
   112  		{
   113  			description:    "Valid - Not Applicable",
   114  			consent:        "1---",
   115  			expectedResult: false,
   116  		},
   117  		{
   118  			description:    "Valid - Empty",
   119  			consent:        "",
   120  			expectedResult: false,
   121  		},
   122  		{
   123  			description:    "Wrong Length",
   124  			consent:        "1NY",
   125  			expectedResult: false,
   126  			expectedError:  "must contain 4 characters",
   127  		},
   128  		{
   129  			description:    "Wrong Version",
   130  			consent:        "2---",
   131  			expectedResult: false,
   132  			expectedError:  "must specify version 1",
   133  		},
   134  		{
   135  			description:    "Explicit Notice Char",
   136  			consent:        "1X--",
   137  			expectedResult: false,
   138  			expectedError:  "must specify 'N', 'Y', or '-' for the explicit notice",
   139  		},
   140  		{
   141  			description:    "Invalid Explicit Notice Case",
   142  			consent:        "1y--",
   143  			expectedResult: false,
   144  			expectedError:  "must specify 'N', 'Y', or '-' for the explicit notice",
   145  		},
   146  		{
   147  			description:    "Invalid Opt-Out Sale Char",
   148  			consent:        "1-X-",
   149  			expectedResult: false,
   150  			expectedError:  "must specify 'N', 'Y', or '-' for the opt-out sale",
   151  		},
   152  		{
   153  			description:    "Invalid Opt-Out Sale Case",
   154  			consent:        "1-y-",
   155  			expectedResult: false,
   156  			expectedError:  "must specify 'N', 'Y', or '-' for the opt-out sale",
   157  		},
   158  		{
   159  			description:    "Invalid LSPA Char",
   160  			consent:        "1--X",
   161  			expectedResult: false,
   162  			expectedError:  "must specify 'N', 'Y', or '-' for the limited service provider agreement",
   163  		},
   164  		{
   165  			description:    "Invalid LSPA Case",
   166  			consent:        "1--y",
   167  			expectedResult: false,
   168  			expectedError:  "must specify 'N', 'Y', or '-' for the limited service provider agreement",
   169  		},
   170  	}
   171  
   172  	for _, test := range testCases {
   173  		result, err := parseConsent(test.consent)
   174  
   175  		if test.expectedError == "" {
   176  			assert.NoError(t, err, test.description)
   177  		} else {
   178  			assert.EqualError(t, err, test.expectedError, test.description)
   179  		}
   180  
   181  		assert.Equal(t, test.expectedResult, result, test.description)
   182  	}
   183  }
   184  
   185  func TestParseNoSaleBidders(t *testing.T) {
   186  	testCases := []struct {
   187  		description                   string
   188  		noSaleBidders                 []string
   189  		validBidders                  []string
   190  		expectedNoSaleForAllBidders   bool
   191  		expectedNoSaleSpecificBidders map[string]struct{}
   192  		expectedError                 string
   193  	}{
   194  		{
   195  			description:                   "Valid - No Bidders",
   196  			noSaleBidders:                 []string{},
   197  			validBidders:                  []string{"a"},
   198  			expectedNoSaleForAllBidders:   false,
   199  			expectedNoSaleSpecificBidders: map[string]struct{}{},
   200  		},
   201  		{
   202  			description:                   "Valid - 1 Bidder",
   203  			noSaleBidders:                 []string{"a"},
   204  			validBidders:                  []string{"a"},
   205  			expectedNoSaleForAllBidders:   false,
   206  			expectedNoSaleSpecificBidders: map[string]struct{}{"a": {}},
   207  		},
   208  		{
   209  			description:                   "Valid - 1+ Bidders",
   210  			noSaleBidders:                 []string{"a", "b"},
   211  			validBidders:                  []string{"a", "b"},
   212  			expectedNoSaleForAllBidders:   false,
   213  			expectedNoSaleSpecificBidders: map[string]struct{}{"a": {}, "b": {}},
   214  		},
   215  		{
   216  			description:                   "Valid - All Bidders",
   217  			noSaleBidders:                 []string{"*"},
   218  			validBidders:                  []string{"a"},
   219  			expectedNoSaleForAllBidders:   true,
   220  			expectedNoSaleSpecificBidders: map[string]struct{}{},
   221  		},
   222  		{
   223  			description:                   "Bidder Not Valid",
   224  			noSaleBidders:                 []string{"b"},
   225  			validBidders:                  []string{"a"},
   226  			expectedError:                 "unrecognized bidder 'b'",
   227  			expectedNoSaleForAllBidders:   false,
   228  			expectedNoSaleSpecificBidders: map[string]struct{}{},
   229  		},
   230  		{
   231  			description:                   "All Bidder Mixed With Other Bidders Is Invalid",
   232  			noSaleBidders:                 []string{"*", "a"},
   233  			validBidders:                  []string{"a"},
   234  			expectedError:                 "can only specify all bidders if no other bidders are provided",
   235  			expectedNoSaleForAllBidders:   false,
   236  			expectedNoSaleSpecificBidders: map[string]struct{}{},
   237  		},
   238  		{
   239  			description:                   "Valid Bidders Case Sensitive",
   240  			noSaleBidders:                 []string{"a"},
   241  			validBidders:                  []string{"A"},
   242  			expectedError:                 "unrecognized bidder 'a'",
   243  			expectedNoSaleForAllBidders:   false,
   244  			expectedNoSaleSpecificBidders: map[string]struct{}{},
   245  		},
   246  	}
   247  
   248  	for _, test := range testCases {
   249  		validBiddersMap := make(map[string]struct{})
   250  		for _, v := range test.validBidders {
   251  			validBiddersMap[v] = struct{}{}
   252  		}
   253  
   254  		resultNoSaleForAllBidders, resultNoSaleSpecificBidders, err := parseNoSaleBidders(test.noSaleBidders, validBiddersMap)
   255  
   256  		if test.expectedError == "" {
   257  			assert.NoError(t, err, test.description+":err")
   258  		} else {
   259  			assert.EqualError(t, err, test.expectedError, test.description+":err")
   260  		}
   261  
   262  		assert.Equal(t, test.expectedNoSaleForAllBidders, resultNoSaleForAllBidders, test.description+":allBidders")
   263  		assert.Equal(t, test.expectedNoSaleSpecificBidders, resultNoSaleSpecificBidders, test.description+":specificBidders")
   264  	}
   265  }
   266  
   267  func TestCanEnforce(t *testing.T) {
   268  	testCases := []struct {
   269  		description string
   270  		policy      ParsedPolicy
   271  		expected    bool
   272  	}{
   273  		{
   274  			description: "Specified",
   275  			policy: ParsedPolicy{
   276  				consentSpecified:      true,
   277  				consentOptOutSale:     false,
   278  				noSaleForAllBidders:   false,
   279  				noSaleSpecificBidders: map[string]struct{}{},
   280  			},
   281  			expected: true,
   282  		},
   283  		{
   284  			description: "Not Specified",
   285  			policy: ParsedPolicy{
   286  				consentSpecified:      false,
   287  				consentOptOutSale:     false,
   288  				noSaleForAllBidders:   false,
   289  				noSaleSpecificBidders: map[string]struct{}{},
   290  			},
   291  			expected: false,
   292  		},
   293  	}
   294  
   295  	for _, test := range testCases {
   296  		result := test.policy.CanEnforce()
   297  		assert.Equal(t, test.expected, result, test.description)
   298  	}
   299  }
   300  
   301  func TestShouldEnforce(t *testing.T) {
   302  	testCases := []struct {
   303  		description string
   304  		policy      ParsedPolicy
   305  		bidder      string
   306  		expected    bool
   307  	}{
   308  		{
   309  			description: "Not Enforced - All Bidders No Sale",
   310  			policy: ParsedPolicy{
   311  				consentSpecified:      true,
   312  				consentOptOutSale:     true,
   313  				noSaleForAllBidders:   true,
   314  				noSaleSpecificBidders: map[string]struct{}{},
   315  			},
   316  			bidder:   "a",
   317  			expected: false,
   318  		},
   319  		{
   320  			description: "Not Enforced - Specific Bidders No Sale",
   321  			policy: ParsedPolicy{
   322  				consentSpecified:      true,
   323  				consentOptOutSale:     true,
   324  				noSaleForAllBidders:   false,
   325  				noSaleSpecificBidders: map[string]struct{}{"a": {}},
   326  			},
   327  			bidder:   "a",
   328  			expected: false,
   329  		},
   330  		{
   331  			description: "Not Enforced - No Bidder No Sale",
   332  			policy: ParsedPolicy{
   333  				consentSpecified:      true,
   334  				consentOptOutSale:     false,
   335  				noSaleForAllBidders:   false,
   336  				noSaleSpecificBidders: map[string]struct{}{},
   337  			},
   338  			bidder:   "a",
   339  			expected: false,
   340  		},
   341  		{
   342  			description: "Not Enforced - No Sale Case Sensitive",
   343  			policy: ParsedPolicy{
   344  				consentSpecified:      true,
   345  				consentOptOutSale:     false,
   346  				noSaleForAllBidders:   false,
   347  				noSaleSpecificBidders: map[string]struct{}{"A": {}},
   348  			},
   349  			bidder:   "a",
   350  			expected: false,
   351  		},
   352  		{
   353  			description: "Enforced - No Bidder No Sale",
   354  			policy: ParsedPolicy{
   355  				consentSpecified:      true,
   356  				consentOptOutSale:     true,
   357  				noSaleForAllBidders:   false,
   358  				noSaleSpecificBidders: map[string]struct{}{},
   359  			},
   360  			bidder:   "a",
   361  			expected: true,
   362  		},
   363  		{
   364  			description: "Enforced - No Sale Case Sensitive",
   365  			policy: ParsedPolicy{
   366  				consentSpecified:      true,
   367  				consentOptOutSale:     true,
   368  				noSaleForAllBidders:   false,
   369  				noSaleSpecificBidders: map[string]struct{}{"A": {}},
   370  			},
   371  			bidder:   "a",
   372  			expected: true,
   373  		},
   374  	}
   375  
   376  	for _, test := range testCases {
   377  		result := test.policy.ShouldEnforce(test.bidder)
   378  		assert.Equal(t, test.expected, result, test.description)
   379  	}
   380  }