github.com/prebid/prebid-server/v2@v2.18.0/config/config_test.go (about) 1 package config 2 3 import ( 4 "bytes" 5 "errors" 6 "net" 7 "os" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/prebid/go-gdpr/consentconstants" 13 "github.com/prebid/prebid-server/v2/openrtb_ext" 14 "github.com/prebid/prebid-server/v2/util/ptrutil" 15 "github.com/spf13/viper" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 var bidderInfos = BidderInfos{ 20 "bidder1": BidderInfo{ 21 Endpoint: "http://bidder1.com", 22 Maintainer: &MaintainerInfo{Email: "maintainer@bidder1.com"}, 23 Capabilities: &CapabilitiesInfo{ 24 App: &PlatformInfo{ 25 MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner}, 26 }, 27 }, 28 }, 29 "bidder2": BidderInfo{ 30 Endpoint: "http://bidder2.com", 31 Maintainer: &MaintainerInfo{Email: "maintainer@bidder2.com"}, 32 Capabilities: &CapabilitiesInfo{ 33 App: &PlatformInfo{ 34 MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner}, 35 }, 36 }, 37 }, 38 } 39 40 func TestExternalCacheURLValidate(t *testing.T) { 41 testCases := []struct { 42 desc string 43 data ExternalCache 44 expErrors int 45 }{ 46 { 47 desc: "With http://", 48 data: ExternalCache{Host: "http://www.google.com", Path: "/path/v1"}, 49 expErrors: 1, 50 }, 51 { 52 desc: "Without http://", 53 data: ExternalCache{Host: "www.google.com", Path: "/path/v1"}, 54 expErrors: 0, 55 }, 56 { 57 desc: "No scheme but '//' prefix", 58 data: ExternalCache{Host: "//www.google.com", Path: "/path/v1"}, 59 expErrors: 1, 60 }, 61 { 62 desc: "// appears twice", 63 data: ExternalCache{Host: "//www.google.com//", Path: "path/v1"}, 64 expErrors: 1, 65 }, 66 { 67 desc: "Host has an only // value", 68 data: ExternalCache{Host: "//", Path: "path/v1"}, 69 expErrors: 1, 70 }, 71 { 72 desc: "only scheme host, valid path", 73 data: ExternalCache{Host: "http://", Path: "/path/v1"}, 74 expErrors: 1, 75 }, 76 { 77 desc: "No host, path only", 78 data: ExternalCache{Host: "", Path: "path/v1"}, 79 expErrors: 1, 80 }, 81 { 82 desc: "No host, nor path", 83 data: ExternalCache{Host: "", Path: ""}, 84 expErrors: 0, 85 }, 86 { 87 desc: "Invalid http at the end", 88 data: ExternalCache{Host: "www.google.com", Path: "http://"}, 89 expErrors: 1, 90 }, 91 { 92 desc: "Host has an unknown scheme", 93 data: ExternalCache{Host: "unknownscheme://host", Path: "/path/v1"}, 94 expErrors: 1, 95 }, 96 { 97 desc: "Wrong colon side in scheme", 98 data: ExternalCache{Host: "http//:www.appnexus.com", Path: "/path/v1"}, 99 expErrors: 1, 100 }, 101 { 102 desc: "Missing '/' in scheme", 103 data: ExternalCache{Host: "http:/www.appnexus.com", Path: "/path/v1"}, 104 expErrors: 1, 105 }, 106 { 107 desc: "host with scheme, no path", 108 data: ExternalCache{Host: "http://www.appnexus.com", Path: ""}, 109 expErrors: 1, 110 }, 111 { 112 desc: "scheme, no host nor path", 113 data: ExternalCache{Host: "http://", Path: ""}, 114 expErrors: 1, 115 }, 116 { 117 desc: "Scheme Invalid", 118 data: ExternalCache{Scheme: "invalid", Host: "www.google.com", Path: "/path/v1"}, 119 expErrors: 1, 120 }, 121 { 122 desc: "Scheme HTTP", 123 data: ExternalCache{Scheme: "http", Host: "www.google.com", Path: "/path/v1"}, 124 expErrors: 0, 125 }, 126 { 127 desc: "Scheme HTTPS", 128 data: ExternalCache{Scheme: "https", Host: "www.google.com", Path: "/path/v1"}, 129 expErrors: 0, 130 }, 131 { 132 desc: "Host with port", 133 data: ExternalCache{Scheme: "https", Host: "localhost:2424", Path: "/path/v1"}, 134 expErrors: 0, 135 }, 136 } 137 for _, test := range testCases { 138 errs := test.data.validate([]error{}) 139 140 assert.Equal(t, test.expErrors, len(errs), "Test case threw unexpected number of errors. Desc: %s errMsg = %v \n", test.desc, errs) 141 } 142 } 143 144 func TestDefaults(t *testing.T) { 145 cfg, _ := newDefaultConfig(t) 146 147 cmpInts(t, "port", 8000, cfg.Port) 148 cmpInts(t, "admin_port", 6060, cfg.AdminPort) 149 cmpInts(t, "auction_timeouts_ms.max", 0, int(cfg.AuctionTimeouts.Max)) 150 cmpInts(t, "max_request_size", 1024*256, int(cfg.MaxRequestSize)) 151 cmpInts(t, "host_cookie.ttl_days", 90, int(cfg.HostCookie.TTL)) 152 cmpInts(t, "host_cookie.max_cookie_size_bytes", 0, cfg.HostCookie.MaxCookieSizeBytes) 153 cmpInts(t, "currency_converter.fetch_interval_seconds", 1800, cfg.CurrencyConverter.FetchIntervalSeconds) 154 cmpStrings(t, "currency_converter.fetch_url", "https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json", cfg.CurrencyConverter.FetchURL) 155 cmpBools(t, "account_required", false, cfg.AccountRequired) 156 cmpInts(t, "metrics.influxdb.collection_rate_seconds", 20, cfg.Metrics.Influxdb.MetricSendInterval) 157 cmpBools(t, "account_adapter_details", false, cfg.Metrics.Disabled.AccountAdapterDetails) 158 cmpBools(t, "account_debug", true, cfg.Metrics.Disabled.AccountDebug) 159 cmpBools(t, "account_stored_responses", true, cfg.Metrics.Disabled.AccountStoredResponses) 160 cmpBools(t, "adapter_connections_metrics", true, cfg.Metrics.Disabled.AdapterConnectionMetrics) 161 cmpBools(t, "adapter_buyeruid_scrubbed", true, cfg.Metrics.Disabled.AdapterBuyerUIDScrubbed) 162 cmpBools(t, "adapter_gdpr_request_blocked", false, cfg.Metrics.Disabled.AdapterGDPRRequestBlocked) 163 cmpStrings(t, "certificates_file", "", cfg.PemCertsFile) 164 cmpInts(t, "stored_requests_timeout_ms", 50, cfg.StoredRequestsTimeout) 165 cmpBools(t, "stored_requests.filesystem.enabled", false, cfg.StoredRequests.Files.Enabled) 166 cmpStrings(t, "stored_requests.filesystem.directorypath", "./stored_requests/data/by_id", cfg.StoredRequests.Files.Path) 167 cmpBools(t, "auto_gen_source_tid", true, cfg.AutoGenSourceTID) 168 cmpBools(t, "generate_bid_id", false, cfg.GenerateBidID) 169 cmpStrings(t, "experiment.adscert.mode", "off", cfg.Experiment.AdCerts.Mode) 170 cmpStrings(t, "experiment.adscert.inprocess.origin", "", cfg.Experiment.AdCerts.InProcess.Origin) 171 cmpStrings(t, "experiment.adscert.inprocess.key", "", cfg.Experiment.AdCerts.InProcess.PrivateKey) 172 cmpInts(t, "experiment.adscert.inprocess.domain_check_interval_seconds", 30, cfg.Experiment.AdCerts.InProcess.DNSCheckIntervalInSeconds) 173 cmpInts(t, "experiment.adscert.inprocess.domain_renewal_interval_seconds", 30, cfg.Experiment.AdCerts.InProcess.DNSRenewalIntervalInSeconds) 174 cmpStrings(t, "experiment.adscert.remote.url", "", cfg.Experiment.AdCerts.Remote.Url) 175 cmpInts(t, "experiment.adscert.remote.signing_timeout_ms", 5, cfg.Experiment.AdCerts.Remote.SigningTimeoutMs) 176 cmpNils(t, "host_schain_node", cfg.HostSChainNode) 177 cmpStrings(t, "datacenter", "", cfg.DataCenter) 178 179 //Assert the price floor default values 180 cmpBools(t, "price_floors.enabled", false, cfg.PriceFloors.Enabled) 181 cmpInts(t, "price_floors.fetcher.worker", 20, cfg.PriceFloors.Fetcher.Worker) 182 cmpInts(t, "price_floors.fetcher.capacity", 20000, cfg.PriceFloors.Fetcher.Capacity) 183 cmpInts(t, "price_floors.fetcher.cache_size_mb", 64, cfg.PriceFloors.Fetcher.CacheSize) 184 cmpInts(t, "price_floors.fetcher.http_client.max_connections_per_host", 0, cfg.PriceFloors.Fetcher.HttpClient.MaxConnsPerHost) 185 cmpInts(t, "price_floors.fetcher.http_client.max_idle_connections", 40, cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConns) 186 cmpInts(t, "price_floors.fetcher.http_client.max_idle_connections_per_host", 2, cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConnsPerHost) 187 cmpInts(t, "price_floors.fetcher.http_client.idle_connection_timeout_seconds", 60, cfg.PriceFloors.Fetcher.HttpClient.IdleConnTimeout) 188 cmpInts(t, "price_floors.fetcher.max_retries", 10, cfg.PriceFloors.Fetcher.MaxRetries) 189 190 // Assert compression related defaults 191 cmpBools(t, "compression.request.enable_gzip", false, cfg.Compression.Request.GZIP) 192 cmpBools(t, "compression.response.enable_gzip", false, cfg.Compression.Response.GZIP) 193 194 cmpBools(t, "account_defaults.price_floors.enabled", false, cfg.AccountDefaults.PriceFloors.Enabled) 195 cmpInts(t, "account_defaults.price_floors.enforce_floors_rate", 100, cfg.AccountDefaults.PriceFloors.EnforceFloorsRate) 196 cmpBools(t, "account_defaults.price_floors.adjust_for_bid_adjustment", true, cfg.AccountDefaults.PriceFloors.AdjustForBidAdjustment) 197 cmpBools(t, "account_defaults.price_floors.enforce_deal_floors", false, cfg.AccountDefaults.PriceFloors.EnforceDealFloors) 198 cmpBools(t, "account_defaults.price_floors.use_dynamic_data", false, cfg.AccountDefaults.PriceFloors.UseDynamicData) 199 cmpInts(t, "account_defaults.price_floors.max_rules", 100, cfg.AccountDefaults.PriceFloors.MaxRule) 200 cmpInts(t, "account_defaults.price_floors.max_schema_dims", 3, cfg.AccountDefaults.PriceFloors.MaxSchemaDims) 201 cmpBools(t, "account_defaults.price_floors.fetch.enabled", false, cfg.AccountDefaults.PriceFloors.Fetcher.Enabled) 202 cmpStrings(t, "account_defaults.price_floors.fetch.url", "", cfg.AccountDefaults.PriceFloors.Fetcher.URL) 203 cmpInts(t, "account_defaults.price_floors.fetch.timeout_ms", 3000, cfg.AccountDefaults.PriceFloors.Fetcher.Timeout) 204 cmpInts(t, "account_defaults.price_floors.fetch.max_file_size_kb", 100, cfg.AccountDefaults.PriceFloors.Fetcher.MaxFileSizeKB) 205 cmpInts(t, "account_defaults.price_floors.fetch.max_rules", 1000, cfg.AccountDefaults.PriceFloors.Fetcher.MaxRules) 206 cmpInts(t, "account_defaults.price_floors.fetch.period_sec", 3600, cfg.AccountDefaults.PriceFloors.Fetcher.Period) 207 cmpInts(t, "account_defaults.price_floors.fetch.max_age_sec", 86400, cfg.AccountDefaults.PriceFloors.Fetcher.MaxAge) 208 cmpInts(t, "account_defaults.price_floors.fetch.max_schema_dims", 0, cfg.AccountDefaults.PriceFloors.Fetcher.MaxSchemaDims) 209 cmpStrings(t, "account_defaults.privacy.topicsdomain", "", cfg.AccountDefaults.Privacy.PrivacySandbox.TopicsDomain) 210 cmpBools(t, "account_defaults.privacy.privacysandbox.cookiedeprecation.enabled", false, cfg.AccountDefaults.Privacy.PrivacySandbox.CookieDeprecation.Enabled) 211 cmpInts(t, "account_defaults.privacy.privacysandbox.cookiedeprecation.ttl_sec", 604800, cfg.AccountDefaults.Privacy.PrivacySandbox.CookieDeprecation.TTLSec) 212 213 cmpBools(t, "account_defaults.events.enabled", false, cfg.AccountDefaults.Events.Enabled) 214 215 cmpBools(t, "hooks.enabled", false, cfg.Hooks.Enabled) 216 cmpStrings(t, "validations.banner_creative_max_size", "skip", cfg.Validations.BannerCreativeMaxSize) 217 cmpStrings(t, "validations.secure_markup", "skip", cfg.Validations.SecureMarkup) 218 cmpInts(t, "validations.max_creative_width", 0, int(cfg.Validations.MaxCreativeWidth)) 219 cmpInts(t, "validations.max_creative_height", 0, int(cfg.Validations.MaxCreativeHeight)) 220 cmpBools(t, "account_modules_metrics", false, cfg.Metrics.Disabled.AccountModulesMetrics) 221 222 cmpBools(t, "tmax_adjustments.enabled", false, cfg.TmaxAdjustments.Enabled) 223 cmpUnsignedInts(t, "tmax_adjustments.bidder_response_duration_min_ms", 0, cfg.TmaxAdjustments.BidderResponseDurationMin) 224 cmpUnsignedInts(t, "tmax_adjustments.bidder_network_latency_buffer_ms", 0, cfg.TmaxAdjustments.BidderNetworkLatencyBuffer) 225 cmpUnsignedInts(t, "tmax_adjustments.pbs_response_preparation_duration_ms", 0, cfg.TmaxAdjustments.PBSResponsePreparationDuration) 226 227 cmpInts(t, "account_defaults.privacy.ipv6.anon_keep_bits", 56, cfg.AccountDefaults.Privacy.IPv6Config.AnonKeepBits) 228 cmpInts(t, "account_defaults.privacy.ipv4.anon_keep_bits", 24, cfg.AccountDefaults.Privacy.IPv4Config.AnonKeepBits) 229 230 //Assert purpose VendorExceptionMap hash tables were built correctly 231 cmpBools(t, "analytics.agma.enabled", false, cfg.Analytics.Agma.Enabled) 232 cmpStrings(t, "analytics.agma.endpoint.timeout", "2s", cfg.Analytics.Agma.Endpoint.Timeout) 233 cmpBools(t, "analytics.agma.endpoint.gzip", false, cfg.Analytics.Agma.Endpoint.Gzip) 234 cmpStrings(t, "analytics.agma.endppoint.url", "https://go.pbs.agma-analytics.de/v1/prebid-server", cfg.Analytics.Agma.Endpoint.Url) 235 cmpStrings(t, "analytics.agma.buffers.size", "2MB", cfg.Analytics.Agma.Buffers.BufferSize) 236 cmpInts(t, "analytics.agma.buffers.count", 100, cfg.Analytics.Agma.Buffers.EventCount) 237 cmpStrings(t, "analytics.agma.buffers.timeout", "15m", cfg.Analytics.Agma.Buffers.Timeout) 238 cmpInts(t, "analytics.agma.accounts", 0, len(cfg.Analytics.Agma.Accounts)) 239 expectedTCF2 := TCF2{ 240 Enabled: true, 241 Purpose1: TCF2Purpose{ 242 EnforceAlgo: TCF2EnforceAlgoFull, 243 EnforceAlgoID: TCF2FullEnforcement, 244 EnforcePurpose: true, 245 EnforceVendors: true, 246 VendorExceptions: []string{}, 247 VendorExceptionMap: map[string]struct{}{}, 248 }, 249 Purpose2: TCF2Purpose{ 250 EnforceAlgo: TCF2EnforceAlgoFull, 251 EnforceAlgoID: TCF2FullEnforcement, 252 EnforcePurpose: true, 253 EnforceVendors: true, 254 VendorExceptions: []string{}, 255 VendorExceptionMap: map[string]struct{}{}, 256 }, 257 Purpose3: TCF2Purpose{ 258 EnforceAlgo: TCF2EnforceAlgoFull, 259 EnforceAlgoID: TCF2FullEnforcement, 260 EnforcePurpose: true, 261 EnforceVendors: true, 262 VendorExceptions: []string{}, 263 VendorExceptionMap: map[string]struct{}{}, 264 }, 265 Purpose4: TCF2Purpose{ 266 EnforceAlgo: TCF2EnforceAlgoFull, 267 EnforceAlgoID: TCF2FullEnforcement, 268 EnforcePurpose: true, 269 EnforceVendors: true, 270 VendorExceptions: []string{}, 271 VendorExceptionMap: map[string]struct{}{}, 272 }, 273 Purpose5: TCF2Purpose{ 274 EnforceAlgo: TCF2EnforceAlgoFull, 275 EnforceAlgoID: TCF2FullEnforcement, 276 EnforcePurpose: true, 277 EnforceVendors: true, 278 VendorExceptions: []string{}, 279 VendorExceptionMap: map[string]struct{}{}, 280 }, 281 Purpose6: TCF2Purpose{ 282 EnforceAlgo: TCF2EnforceAlgoFull, 283 EnforceAlgoID: TCF2FullEnforcement, 284 EnforcePurpose: true, 285 EnforceVendors: true, 286 VendorExceptions: []string{}, 287 VendorExceptionMap: map[string]struct{}{}, 288 }, 289 Purpose7: TCF2Purpose{ 290 EnforceAlgo: TCF2EnforceAlgoFull, 291 EnforceAlgoID: TCF2FullEnforcement, 292 EnforcePurpose: true, 293 EnforceVendors: true, 294 VendorExceptions: []string{}, 295 VendorExceptionMap: map[string]struct{}{}, 296 }, 297 Purpose8: TCF2Purpose{ 298 EnforceAlgo: TCF2EnforceAlgoFull, 299 EnforceAlgoID: TCF2FullEnforcement, 300 EnforcePurpose: true, 301 EnforceVendors: true, 302 VendorExceptions: []string{}, 303 VendorExceptionMap: map[string]struct{}{}, 304 }, 305 Purpose9: TCF2Purpose{ 306 EnforceAlgo: TCF2EnforceAlgoFull, 307 EnforceAlgoID: TCF2FullEnforcement, 308 EnforcePurpose: true, 309 EnforceVendors: true, 310 VendorExceptions: []string{}, 311 VendorExceptionMap: map[string]struct{}{}, 312 }, 313 Purpose10: TCF2Purpose{ 314 EnforceAlgo: TCF2EnforceAlgoFull, 315 EnforceAlgoID: TCF2FullEnforcement, 316 EnforcePurpose: true, 317 EnforceVendors: true, 318 VendorExceptions: []string{}, 319 VendorExceptionMap: map[string]struct{}{}, 320 }, 321 SpecialFeature1: TCF2SpecialFeature{ 322 Enforce: true, 323 VendorExceptions: []openrtb_ext.BidderName{}, 324 VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, 325 }, 326 PurposeOneTreatment: TCF2PurposeOneTreatment{ 327 Enabled: true, 328 AccessAllowed: true, 329 }, 330 } 331 expectedTCF2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 332 1: &expectedTCF2.Purpose1, 333 2: &expectedTCF2.Purpose2, 334 3: &expectedTCF2.Purpose3, 335 4: &expectedTCF2.Purpose4, 336 5: &expectedTCF2.Purpose5, 337 6: &expectedTCF2.Purpose6, 338 7: &expectedTCF2.Purpose7, 339 8: &expectedTCF2.Purpose8, 340 9: &expectedTCF2.Purpose9, 341 10: &expectedTCF2.Purpose10, 342 } 343 assert.Equal(t, expectedTCF2, cfg.GDPR.TCF2, "gdpr.tcf2") 344 } 345 346 // When adding a new field, make sure the indentations are spaces not tabs otherwise read config may fail to parse the new field value. 347 var fullConfig = []byte(` 348 gdpr: 349 host_vendor_id: 15 350 default_value: "1" 351 non_standard_publishers: ["pub1", "pub2"] 352 eea_countries: ["eea1", "eea2"] 353 tcf2: 354 purpose1: 355 enforce_vendors: false 356 vendor_exceptions: ["foo1a", "foo1b"] 357 purpose2: 358 enforce_algo: "full" 359 enforce_purpose: false 360 enforce_vendors: false 361 vendor_exceptions: ["foo2"] 362 purpose3: 363 enforce_algo: "basic" 364 enforce_vendors: false 365 vendor_exceptions: ["foo3"] 366 purpose4: 367 enforce_vendors: false 368 vendor_exceptions: ["foo4"] 369 purpose5: 370 enforce_vendors: false 371 vendor_exceptions: ["foo5"] 372 purpose6: 373 enforce_vendors: false 374 vendor_exceptions: ["foo6"] 375 purpose7: 376 enforce_vendors: false 377 vendor_exceptions: ["foo7"] 378 purpose8: 379 enforce_vendors: false 380 vendor_exceptions: ["foo8"] 381 purpose9: 382 enforce_vendors: false 383 vendor_exceptions: ["foo9"] 384 purpose10: 385 enforce_vendors: false 386 vendor_exceptions: ["foo10"] 387 special_feature1: 388 vendor_exceptions: ["fooSP1"] 389 ccpa: 390 enforce: true 391 lmt: 392 enforce: true 393 host_cookie: 394 cookie_name: userid 395 family: prebid 396 domain: cookies.prebid.org 397 opt_out_url: http://prebid.org/optout 398 opt_in_url: http://prebid.org/optin 399 max_cookie_size_bytes: 32768 400 external_url: http://prebid-server.prebid.org/ 401 host: prebid-server.prebid.org 402 port: 1234 403 admin_port: 5678 404 stored_requests_timeout_ms: 75 405 compression: 406 request: 407 enable_gzip: true 408 response: 409 enable_gzip: false 410 garbage_collector_threshold: 1 411 datacenter: "1" 412 auction_timeouts_ms: 413 max: 123 414 default: 50 415 cache: 416 scheme: http 417 host: prebidcache.net 418 query: uuid=%PBS_CACHE_UUID% 419 external_cache: 420 scheme: https 421 host: www.externalprebidcache.net 422 path: /endpoints/cache 423 http_client: 424 max_connections_per_host: 10 425 max_idle_connections: 500 426 max_idle_connections_per_host: 20 427 idle_connection_timeout_seconds: 30 428 http_client_cache: 429 max_connections_per_host: 5 430 max_idle_connections: 1 431 max_idle_connections_per_host: 2 432 idle_connection_timeout_seconds: 3 433 currency_converter: 434 fetch_url: https://currency.prebid.org 435 fetch_interval_seconds: 1800 436 recaptcha_secret: asdfasdfasdfasdf 437 metrics: 438 influxdb: 439 host: upstream:8232 440 database: metricsdb 441 measurement: anyMeasurement 442 username: admin 443 password: admin1324 444 align_timestamps: true 445 metric_send_interval: 30 446 disabled_metrics: 447 account_adapter_details: true 448 account_debug: false 449 account_stored_responses: false 450 adapter_connections_metrics: true 451 adapter_buyeruid_scrubbed: false 452 adapter_gdpr_request_blocked: true 453 account_modules_metrics: true 454 blacklisted_apps: ["spamAppID","sketchy-app-id"] 455 account_required: true 456 auto_gen_source_tid: false 457 certificates_file: /etc/ssl/cert.pem 458 request_validation: 459 ipv4_private_networks: ["1.1.1.0/24"] 460 ipv6_private_networks: ["1111::/16", "2222::/16"] 461 generate_bid_id: true 462 host_schain_node: 463 asi: "pbshostcompany.com" 464 sid: "00001" 465 rid: "BidRequest" 466 hp: 1 467 validations: 468 banner_creative_max_size: "skip" 469 secure_markup: "skip" 470 max_creative_width: 0 471 max_creative_height: 0 472 experiment: 473 adscert: 474 mode: inprocess 475 inprocess: 476 origin: "http://test.com" 477 key: "ABC123" 478 domain_check_interval_seconds: 40 479 domain_renewal_interval_seconds : 60 480 remote: 481 url: "" 482 signing_timeout_ms: 10 483 hooks: 484 enabled: true 485 price_floors: 486 enabled: true 487 fetcher: 488 worker: 20 489 capacity: 20000 490 cache_size_mb: 8 491 http_client: 492 max_connections_per_host: 5 493 max_idle_connections: 1 494 max_idle_connections_per_host: 2 495 idle_connection_timeout_seconds: 10 496 max_retries: 5 497 account_defaults: 498 events: 499 enabled: true 500 price_floors: 501 enabled: true 502 enforce_floors_rate: 50 503 adjust_for_bid_adjustment: false 504 enforce_deal_floors: true 505 use_dynamic_data: true 506 max_rules: 120 507 max_schema_dims: 5 508 fetch: 509 enabled: true 510 url: http://test.com/floors 511 timeout_ms: 500 512 max_file_size_kb: 200 513 max_rules: 500 514 period_sec: 2000 515 max_age_sec: 6000 516 max_schema_dims: 10 517 bidadjustments: 518 mediatype: 519 '*': 520 '*': 521 '*': 522 - adjtype: multiplier 523 value: 1.01 524 currency: USD 525 video-instream: 526 bidder: 527 deal_id: 528 - adjtype: cpm 529 value: 1.02 530 currency: EUR 531 privacy: 532 ipv6: 533 anon_keep_bits: 50 534 ipv4: 535 anon_keep_bits: 20 536 dsa: 537 default: "{\"dsarequired\":3,\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}" 538 gdpr_only: true 539 privacysandbox: 540 topicsdomain: "test.com" 541 cookiedeprecation: 542 enabled: true 543 ttl_sec: 86400 544 tmax_adjustments: 545 enabled: true 546 bidder_response_duration_min_ms: 700 547 bidder_network_latency_buffer_ms: 100 548 pbs_response_preparation_duration_ms: 100 549 analytics: 550 agma: 551 enabled: true 552 endpoint: 553 url: "http://test.com" 554 timeout: "5s" 555 gzip: false 556 buffers: 557 size: 10MB 558 count: 111 559 timeout: 5m 560 accounts: 561 - code: agma-code 562 publisher_id: publisher-id 563 site_app_id: site-or-app-id 564 `) 565 566 func cmpStrings(t *testing.T, key, expected, actual string) { 567 t.Helper() 568 assert.Equal(t, expected, actual, "%s: %s != %s", key, expected, actual) 569 } 570 571 func cmpInts(t *testing.T, key string, expected, actual int) { 572 t.Helper() 573 assert.Equal(t, expected, actual, "%s: %d != %d", key, expected, actual) 574 } 575 576 func cmpUnsignedInts(t *testing.T, key string, expected, actual uint) { 577 t.Helper() 578 assert.Equal(t, expected, actual, "%s: %d != %d", key, expected, actual) 579 } 580 581 func cmpInt8s(t *testing.T, key string, expected, actual *int8) { 582 t.Helper() 583 assert.Equal(t, expected, actual, "%s: %d != %d", key, expected, actual) 584 } 585 586 func cmpBools(t *testing.T, key string, expected, actual bool) { 587 t.Helper() 588 assert.Equal(t, expected, actual, "%s: %t != %t", key, expected, actual) 589 } 590 591 func cmpNils(t *testing.T, key string, a interface{}) { 592 t.Helper() 593 assert.Nilf(t, a, "%s: %t != nil", key, a) 594 } 595 596 func TestFullConfig(t *testing.T) { 597 int8One := int8(1) 598 599 v := viper.New() 600 SetupViper(v, "", bidderInfos) 601 v.SetConfigType("yaml") 602 v.ReadConfig(bytes.NewBuffer(fullConfig)) 603 cfg, err := New(v, bidderInfos, mockNormalizeBidderName) 604 assert.NoError(t, err, "Setting up config should work but it doesn't") 605 cmpStrings(t, "cookie domain", "cookies.prebid.org", cfg.HostCookie.Domain) 606 cmpStrings(t, "cookie name", "userid", cfg.HostCookie.CookieName) 607 cmpStrings(t, "cookie family", "prebid", cfg.HostCookie.Family) 608 cmpStrings(t, "opt out", "http://prebid.org/optout", cfg.HostCookie.OptOutURL) 609 cmpStrings(t, "opt in", "http://prebid.org/optin", cfg.HostCookie.OptInURL) 610 cmpStrings(t, "external url", "http://prebid-server.prebid.org/", cfg.ExternalURL) 611 cmpStrings(t, "host", "prebid-server.prebid.org", cfg.Host) 612 cmpInts(t, "port", 1234, cfg.Port) 613 cmpInts(t, "admin_port", 5678, cfg.AdminPort) 614 cmpInts(t, "garbage_collector_threshold", 1, cfg.GarbageCollectorThreshold) 615 cmpInts(t, "auction_timeouts_ms.default", 50, int(cfg.AuctionTimeouts.Default)) 616 cmpInts(t, "auction_timeouts_ms.max", 123, int(cfg.AuctionTimeouts.Max)) 617 cmpInts(t, "stored_request_timeout_ms", 75, cfg.StoredRequestsTimeout) 618 cmpStrings(t, "cache.scheme", "http", cfg.CacheURL.Scheme) 619 cmpStrings(t, "cache.host", "prebidcache.net", cfg.CacheURL.Host) 620 cmpStrings(t, "cache.query", "uuid=%PBS_CACHE_UUID%", cfg.CacheURL.Query) 621 cmpStrings(t, "external_cache.scheme", "https", cfg.ExtCacheURL.Scheme) 622 cmpStrings(t, "external_cache.host", "www.externalprebidcache.net", cfg.ExtCacheURL.Host) 623 cmpStrings(t, "external_cache.path", "/endpoints/cache", cfg.ExtCacheURL.Path) 624 cmpInts(t, "http_client.max_connections_per_host", 10, cfg.Client.MaxConnsPerHost) 625 cmpInts(t, "http_client.max_idle_connections", 500, cfg.Client.MaxIdleConns) 626 cmpInts(t, "http_client.max_idle_connections_per_host", 20, cfg.Client.MaxIdleConnsPerHost) 627 cmpInts(t, "http_client.idle_connection_timeout_seconds", 30, cfg.Client.IdleConnTimeout) 628 cmpInts(t, "http_client_cache.max_connections_per_host", 5, cfg.CacheClient.MaxConnsPerHost) 629 cmpInts(t, "http_client_cache.max_idle_connections", 1, cfg.CacheClient.MaxIdleConns) 630 cmpInts(t, "http_client_cache.max_idle_connections_per_host", 2, cfg.CacheClient.MaxIdleConnsPerHost) 631 cmpInts(t, "http_client_cache.idle_connection_timeout_seconds", 3, cfg.CacheClient.IdleConnTimeout) 632 cmpInts(t, "gdpr.host_vendor_id", 15, cfg.GDPR.HostVendorID) 633 cmpStrings(t, "gdpr.default_value", "1", cfg.GDPR.DefaultValue) 634 cmpStrings(t, "host_schain_node.asi", "pbshostcompany.com", cfg.HostSChainNode.ASI) 635 cmpStrings(t, "host_schain_node.sid", "00001", cfg.HostSChainNode.SID) 636 cmpStrings(t, "host_schain_node.rid", "BidRequest", cfg.HostSChainNode.RID) 637 cmpInt8s(t, "host_schain_node.hp", &int8One, cfg.HostSChainNode.HP) 638 cmpStrings(t, "datacenter", "1", cfg.DataCenter) 639 cmpStrings(t, "validations.banner_creative_max_size", "skip", cfg.Validations.BannerCreativeMaxSize) 640 cmpStrings(t, "validations.secure_markup", "skip", cfg.Validations.SecureMarkup) 641 cmpInts(t, "validations.max_creative_width", 0, int(cfg.Validations.MaxCreativeWidth)) 642 cmpInts(t, "validations.max_creative_height", 0, int(cfg.Validations.MaxCreativeHeight)) 643 cmpBools(t, "tmax_adjustments.enabled", true, cfg.TmaxAdjustments.Enabled) 644 cmpUnsignedInts(t, "tmax_adjustments.bidder_response_duration_min_ms", 700, cfg.TmaxAdjustments.BidderResponseDurationMin) 645 cmpUnsignedInts(t, "tmax_adjustments.bidder_network_latency_buffer_ms", 100, cfg.TmaxAdjustments.BidderNetworkLatencyBuffer) 646 cmpUnsignedInts(t, "tmax_adjustments.pbs_response_preparation_duration_ms", 100, cfg.TmaxAdjustments.PBSResponsePreparationDuration) 647 648 //Assert the price floor values 649 cmpBools(t, "price_floors.enabled", true, cfg.PriceFloors.Enabled) 650 cmpInts(t, "price_floors.fetcher.worker", 20, cfg.PriceFloors.Fetcher.Worker) 651 cmpInts(t, "price_floors.fetcher.capacity", 20000, cfg.PriceFloors.Fetcher.Capacity) 652 cmpInts(t, "price_floors.fetcher.cache_size_mb", 8, cfg.PriceFloors.Fetcher.CacheSize) 653 cmpInts(t, "price_floors.fetcher.http_client.max_connections_per_host", 5, cfg.PriceFloors.Fetcher.HttpClient.MaxConnsPerHost) 654 cmpInts(t, "price_floors.fetcher.http_client.max_idle_connections", 1, cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConns) 655 cmpInts(t, "price_floors.fetcher.http_client.max_idle_connections_per_host", 2, cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConnsPerHost) 656 cmpInts(t, "price_floors.fetcher.http_client.idle_connection_timeout_seconds", 10, cfg.PriceFloors.Fetcher.HttpClient.IdleConnTimeout) 657 cmpInts(t, "price_floors.fetcher.max_retries", 5, cfg.PriceFloors.Fetcher.MaxRetries) 658 cmpBools(t, "account_defaults.price_floors.enabled", true, cfg.AccountDefaults.PriceFloors.Enabled) 659 cmpInts(t, "account_defaults.price_floors.enforce_floors_rate", 50, cfg.AccountDefaults.PriceFloors.EnforceFloorsRate) 660 cmpBools(t, "account_defaults.price_floors.adjust_for_bid_adjustment", false, cfg.AccountDefaults.PriceFloors.AdjustForBidAdjustment) 661 cmpBools(t, "account_defaults.price_floors.enforce_deal_floors", true, cfg.AccountDefaults.PriceFloors.EnforceDealFloors) 662 cmpBools(t, "account_defaults.price_floors.use_dynamic_data", true, cfg.AccountDefaults.PriceFloors.UseDynamicData) 663 cmpInts(t, "account_defaults.price_floors.max_rules", 120, cfg.AccountDefaults.PriceFloors.MaxRule) 664 cmpInts(t, "account_defaults.price_floors.max_schema_dims", 5, cfg.AccountDefaults.PriceFloors.MaxSchemaDims) 665 cmpBools(t, "account_defaults.price_floors.fetch.enabled", true, cfg.AccountDefaults.PriceFloors.Fetcher.Enabled) 666 cmpStrings(t, "account_defaults.price_floors.fetch.url", "http://test.com/floors", cfg.AccountDefaults.PriceFloors.Fetcher.URL) 667 cmpInts(t, "account_defaults.price_floors.fetch.timeout_ms", 500, cfg.AccountDefaults.PriceFloors.Fetcher.Timeout) 668 cmpInts(t, "account_defaults.price_floors.fetch.max_file_size_kb", 200, cfg.AccountDefaults.PriceFloors.Fetcher.MaxFileSizeKB) 669 cmpInts(t, "account_defaults.price_floors.fetch.max_rules", 500, cfg.AccountDefaults.PriceFloors.Fetcher.MaxRules) 670 cmpInts(t, "account_defaults.price_floors.fetch.period_sec", 2000, cfg.AccountDefaults.PriceFloors.Fetcher.Period) 671 cmpInts(t, "account_defaults.price_floors.fetch.max_age_sec", 6000, cfg.AccountDefaults.PriceFloors.Fetcher.MaxAge) 672 cmpInts(t, "account_defaults.price_floors.fetch.max_schema_dims", 10, cfg.AccountDefaults.PriceFloors.Fetcher.MaxSchemaDims) 673 674 // Assert the DSA was correctly unmarshalled and DefaultUnpacked was built correctly 675 expectedDSA := AccountDSA{ 676 Default: "{\"dsarequired\":3,\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}", 677 DefaultUnpacked: &openrtb_ext.ExtRegsDSA{ 678 Required: ptrutil.ToPtr[int8](3), 679 PubRender: ptrutil.ToPtr[int8](1), 680 DataToPub: ptrutil.ToPtr[int8](2), 681 Transparency: []openrtb_ext.ExtBidDSATransparency{ 682 { 683 Domain: "domain.com", 684 Params: []int{1}, 685 }, 686 }, 687 }, 688 GDPROnly: true, 689 } 690 assert.Equal(t, &expectedDSA, cfg.AccountDefaults.Privacy.DSA) 691 692 cmpBools(t, "account_defaults.events.enabled", true, cfg.AccountDefaults.Events.Enabled) 693 694 cmpInts(t, "account_defaults.privacy.ipv6.anon_keep_bits", 50, cfg.AccountDefaults.Privacy.IPv6Config.AnonKeepBits) 695 cmpInts(t, "account_defaults.privacy.ipv4.anon_keep_bits", 20, cfg.AccountDefaults.Privacy.IPv4Config.AnonKeepBits) 696 697 cmpStrings(t, "account_defaults.privacy.topicsdomain", "test.com", cfg.AccountDefaults.Privacy.PrivacySandbox.TopicsDomain) 698 cmpBools(t, "account_defaults.privacy.cookiedeprecation.enabled", true, cfg.AccountDefaults.Privacy.PrivacySandbox.CookieDeprecation.Enabled) 699 cmpInts(t, "account_defaults.privacy.cookiedeprecation.ttl_sec", 86400, cfg.AccountDefaults.Privacy.PrivacySandbox.CookieDeprecation.TTLSec) 700 701 // Assert compression related defaults 702 cmpBools(t, "compression.request.enable_gzip", true, cfg.Compression.Request.GZIP) 703 cmpBools(t, "compression.response.enable_gzip", false, cfg.Compression.Response.GZIP) 704 705 //Assert the NonStandardPublishers was correctly unmarshalled 706 assert.Equal(t, []string{"pub1", "pub2"}, cfg.GDPR.NonStandardPublishers, "gdpr.non_standard_publishers") 707 assert.Equal(t, map[string]struct{}{"pub1": {}, "pub2": {}}, cfg.GDPR.NonStandardPublisherMap, "gdpr.non_standard_publishers Hash Map") 708 709 // Assert EEA Countries was correctly unmarshalled and the EEACountriesMap built correctly. 710 assert.Equal(t, []string{"eea1", "eea2"}, cfg.GDPR.EEACountries, "gdpr.eea_countries") 711 assert.Equal(t, map[string]struct{}{"eea1": {}, "eea2": {}}, cfg.GDPR.EEACountriesMap, "gdpr.eea_countries Hash Map") 712 713 cmpBools(t, "ccpa.enforce", true, cfg.CCPA.Enforce) 714 cmpBools(t, "lmt.enforce", true, cfg.LMT.Enforce) 715 716 //Assert the NonStandardPublishers was correctly unmarshalled 717 cmpStrings(t, "blacklisted_apps", "spamAppID", cfg.BlacklistedApps[0]) 718 cmpStrings(t, "blacklisted_apps", "sketchy-app-id", cfg.BlacklistedApps[1]) 719 720 //Assert the BlacklistedAppMap hash table was built correctly 721 for i := 0; i < len(cfg.BlacklistedApps); i++ { 722 cmpBools(t, "cfg.BlacklistedAppMap", true, cfg.BlacklistedAppMap[cfg.BlacklistedApps[i]]) 723 } 724 725 //Assert purpose VendorExceptionMap hash tables were built correctly 726 expectedTCF2 := TCF2{ 727 Enabled: true, 728 Purpose1: TCF2Purpose{ 729 EnforceAlgo: TCF2EnforceAlgoFull, 730 EnforceAlgoID: TCF2FullEnforcement, 731 EnforcePurpose: true, 732 EnforceVendors: false, 733 VendorExceptions: []string{"foo1a", "foo1b"}, 734 VendorExceptionMap: map[string]struct{}{"foo1a": {}, "foo1b": {}}, 735 }, 736 Purpose2: TCF2Purpose{ 737 EnforceAlgo: TCF2EnforceAlgoFull, 738 EnforceAlgoID: TCF2FullEnforcement, 739 EnforcePurpose: false, 740 EnforceVendors: false, 741 VendorExceptions: []string{"foo2"}, 742 VendorExceptionMap: map[string]struct{}{"foo2": {}}, 743 }, 744 Purpose3: TCF2Purpose{ 745 EnforceAlgo: TCF2EnforceAlgoBasic, 746 EnforceAlgoID: TCF2BasicEnforcement, 747 EnforcePurpose: true, 748 EnforceVendors: false, 749 VendorExceptions: []string{"foo3"}, 750 VendorExceptionMap: map[string]struct{}{"foo3": {}}, 751 }, 752 Purpose4: TCF2Purpose{ 753 EnforceAlgo: TCF2EnforceAlgoFull, 754 EnforceAlgoID: TCF2FullEnforcement, 755 EnforcePurpose: true, 756 EnforceVendors: false, 757 VendorExceptions: []string{"foo4"}, 758 VendorExceptionMap: map[string]struct{}{"foo4": {}}, 759 }, 760 Purpose5: TCF2Purpose{ 761 EnforceAlgo: TCF2EnforceAlgoFull, 762 EnforceAlgoID: TCF2FullEnforcement, 763 EnforcePurpose: true, 764 EnforceVendors: false, 765 VendorExceptions: []string{"foo5"}, 766 VendorExceptionMap: map[string]struct{}{"foo5": {}}, 767 }, 768 Purpose6: TCF2Purpose{ 769 EnforceAlgo: TCF2EnforceAlgoFull, 770 EnforceAlgoID: TCF2FullEnforcement, 771 EnforcePurpose: true, 772 EnforceVendors: false, 773 VendorExceptions: []string{"foo6"}, 774 VendorExceptionMap: map[string]struct{}{"foo6": {}}, 775 }, 776 Purpose7: TCF2Purpose{ 777 EnforceAlgo: TCF2EnforceAlgoFull, 778 EnforceAlgoID: TCF2FullEnforcement, 779 EnforcePurpose: true, 780 EnforceVendors: false, 781 VendorExceptions: []string{"foo7"}, 782 VendorExceptionMap: map[string]struct{}{"foo7": {}}, 783 }, 784 Purpose8: TCF2Purpose{ 785 EnforceAlgo: TCF2EnforceAlgoFull, 786 EnforceAlgoID: TCF2FullEnforcement, 787 EnforcePurpose: true, 788 EnforceVendors: false, 789 VendorExceptions: []string{"foo8"}, 790 VendorExceptionMap: map[string]struct{}{"foo8": {}}, 791 }, 792 Purpose9: TCF2Purpose{ 793 EnforceAlgo: TCF2EnforceAlgoFull, 794 EnforceAlgoID: TCF2FullEnforcement, 795 EnforcePurpose: true, 796 EnforceVendors: false, 797 VendorExceptions: []string{"foo9"}, 798 VendorExceptionMap: map[string]struct{}{"foo9": {}}, 799 }, 800 Purpose10: TCF2Purpose{ 801 EnforceAlgo: TCF2EnforceAlgoFull, 802 EnforceAlgoID: TCF2FullEnforcement, 803 EnforcePurpose: true, 804 EnforceVendors: false, 805 VendorExceptions: []string{"foo10"}, 806 VendorExceptionMap: map[string]struct{}{"foo10": {}}, 807 }, 808 SpecialFeature1: TCF2SpecialFeature{ 809 Enforce: true, // true by default 810 VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("fooSP1")}, 811 VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("fooSP1"): {}}, 812 }, 813 PurposeOneTreatment: TCF2PurposeOneTreatment{ 814 Enabled: true, // true by default 815 AccessAllowed: true, // true by default 816 }, 817 } 818 expectedTCF2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 819 1: &expectedTCF2.Purpose1, 820 2: &expectedTCF2.Purpose2, 821 3: &expectedTCF2.Purpose3, 822 4: &expectedTCF2.Purpose4, 823 5: &expectedTCF2.Purpose5, 824 6: &expectedTCF2.Purpose6, 825 7: &expectedTCF2.Purpose7, 826 8: &expectedTCF2.Purpose8, 827 9: &expectedTCF2.Purpose9, 828 10: &expectedTCF2.Purpose10, 829 } 830 831 expectedBidAdjustments := &openrtb_ext.ExtRequestPrebidBidAdjustments{ 832 MediaType: openrtb_ext.MediaType{ 833 WildCard: map[openrtb_ext.BidderName]openrtb_ext.AdjustmentsByDealID{ 834 "*": { 835 "*": []openrtb_ext.Adjustment{{Type: "multiplier", Value: 1.01, Currency: "USD"}}, 836 }, 837 }, 838 VideoInstream: map[openrtb_ext.BidderName]openrtb_ext.AdjustmentsByDealID{ 839 "bidder": { 840 "deal_id": []openrtb_ext.Adjustment{{Type: "cpm", Value: 1.02, Currency: "EUR"}}, 841 }, 842 }, 843 }, 844 } 845 assert.Equal(t, expectedTCF2, cfg.GDPR.TCF2, "gdpr.tcf2") 846 assert.Equal(t, expectedBidAdjustments, cfg.AccountDefaults.BidAdjustments) 847 848 cmpStrings(t, "currency_converter.fetch_url", "https://currency.prebid.org", cfg.CurrencyConverter.FetchURL) 849 cmpInts(t, "currency_converter.fetch_interval_seconds", 1800, cfg.CurrencyConverter.FetchIntervalSeconds) 850 cmpStrings(t, "recaptcha_secret", "asdfasdfasdfasdf", cfg.RecaptchaSecret) 851 cmpStrings(t, "metrics.influxdb.host", "upstream:8232", cfg.Metrics.Influxdb.Host) 852 cmpStrings(t, "metrics.influxdb.database", "metricsdb", cfg.Metrics.Influxdb.Database) 853 cmpStrings(t, "metrics.influxdb.measurement", "anyMeasurement", cfg.Metrics.Influxdb.Measurement) 854 cmpStrings(t, "metrics.influxdb.username", "admin", cfg.Metrics.Influxdb.Username) 855 cmpStrings(t, "metrics.influxdb.password", "admin1324", cfg.Metrics.Influxdb.Password) 856 cmpBools(t, "metrics.influxdb.align_timestamps", true, cfg.Metrics.Influxdb.AlignTimestamps) 857 cmpInts(t, "metrics.influxdb.metric_send_interval", 30, cfg.Metrics.Influxdb.MetricSendInterval) 858 cmpStrings(t, "", "http://prebidcache.net", cfg.CacheURL.GetBaseURL()) 859 cmpStrings(t, "", "http://prebidcache.net/cache?uuid=a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11", cfg.GetCachedAssetURL("a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11")) 860 cmpBools(t, "account_required", true, cfg.AccountRequired) 861 cmpBools(t, "auto_gen_source_tid", false, cfg.AutoGenSourceTID) 862 cmpBools(t, "account_adapter_details", true, cfg.Metrics.Disabled.AccountAdapterDetails) 863 cmpBools(t, "account_debug", false, cfg.Metrics.Disabled.AccountDebug) 864 cmpBools(t, "account_stored_responses", false, cfg.Metrics.Disabled.AccountStoredResponses) 865 cmpBools(t, "adapter_connections_metrics", true, cfg.Metrics.Disabled.AdapterConnectionMetrics) 866 cmpBools(t, "adapter_buyeruid_scrubbed", false, cfg.Metrics.Disabled.AdapterBuyerUIDScrubbed) 867 cmpBools(t, "adapter_gdpr_request_blocked", true, cfg.Metrics.Disabled.AdapterGDPRRequestBlocked) 868 cmpStrings(t, "certificates_file", "/etc/ssl/cert.pem", cfg.PemCertsFile) 869 cmpStrings(t, "request_validation.ipv4_private_networks", "1.1.1.0/24", cfg.RequestValidation.IPv4PrivateNetworks[0]) 870 cmpStrings(t, "request_validation.ipv6_private_networks", "1111::/16", cfg.RequestValidation.IPv6PrivateNetworks[0]) 871 cmpStrings(t, "request_validation.ipv6_private_networks", "2222::/16", cfg.RequestValidation.IPv6PrivateNetworks[1]) 872 cmpBools(t, "generate_bid_id", true, cfg.GenerateBidID) 873 cmpStrings(t, "debug.override_token", "", cfg.Debug.OverrideToken) 874 cmpStrings(t, "experiment.adscert.mode", "inprocess", cfg.Experiment.AdCerts.Mode) 875 cmpStrings(t, "experiment.adscert.inprocess.origin", "http://test.com", cfg.Experiment.AdCerts.InProcess.Origin) 876 cmpStrings(t, "experiment.adscert.inprocess.key", "ABC123", cfg.Experiment.AdCerts.InProcess.PrivateKey) 877 cmpInts(t, "experiment.adscert.inprocess.domain_check_interval_seconds", 40, cfg.Experiment.AdCerts.InProcess.DNSCheckIntervalInSeconds) 878 cmpInts(t, "experiment.adscert.inprocess.domain_renewal_interval_seconds", 60, cfg.Experiment.AdCerts.InProcess.DNSRenewalIntervalInSeconds) 879 cmpStrings(t, "experiment.adscert.remote.url", "", cfg.Experiment.AdCerts.Remote.Url) 880 cmpInts(t, "experiment.adscert.remote.signing_timeout_ms", 10, cfg.Experiment.AdCerts.Remote.SigningTimeoutMs) 881 cmpBools(t, "hooks.enabled", true, cfg.Hooks.Enabled) 882 cmpBools(t, "account_modules_metrics", true, cfg.Metrics.Disabled.AccountModulesMetrics) 883 cmpBools(t, "analytics.agma.enabled", true, cfg.Analytics.Agma.Enabled) 884 cmpStrings(t, "analytics.agma.endpoint.timeout", "5s", cfg.Analytics.Agma.Endpoint.Timeout) 885 cmpBools(t, "analytics.agma.endpoint.gzip", false, cfg.Analytics.Agma.Endpoint.Gzip) 886 cmpStrings(t, "analytics.agma.endpoint.url", "http://test.com", cfg.Analytics.Agma.Endpoint.Url) 887 cmpStrings(t, "analytics.agma.buffers.size", "10MB", cfg.Analytics.Agma.Buffers.BufferSize) 888 cmpInts(t, "analytics.agma.buffers.count", 111, cfg.Analytics.Agma.Buffers.EventCount) 889 cmpStrings(t, "analytics.agma.buffers.timeout", "5m", cfg.Analytics.Agma.Buffers.Timeout) 890 cmpStrings(t, "analytics.agma.accounts.0.publisher_id", "publisher-id", cfg.Analytics.Agma.Accounts[0].PublisherId) 891 cmpStrings(t, "analytics.agma.accounts.0.code", "agma-code", cfg.Analytics.Agma.Accounts[0].Code) 892 cmpStrings(t, "analytics.agma.accounts.0.site_app_id", "site-or-app-id", cfg.Analytics.Agma.Accounts[0].SiteAppId) 893 } 894 895 func TestValidateConfig(t *testing.T) { 896 cfg := Configuration{ 897 GDPR: GDPR{ 898 DefaultValue: "1", 899 TCF2: TCF2{ 900 Purpose1: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoBasic}, 901 Purpose2: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoFull}, 902 Purpose3: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoBasic}, 903 Purpose4: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoFull}, 904 Purpose5: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoBasic}, 905 Purpose6: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoFull}, 906 Purpose7: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoBasic}, 907 Purpose8: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoFull}, 908 Purpose9: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoBasic}, 909 Purpose10: TCF2Purpose{EnforceAlgo: TCF2EnforceAlgoFull}, 910 }, 911 }, 912 StoredRequests: StoredRequests{ 913 Files: FileFetcherConfig{Enabled: true}, 914 InMemoryCache: InMemoryCache{ 915 Type: "none", 916 }, 917 }, 918 StoredRequestsTimeout: 50, 919 StoredVideo: StoredRequests{ 920 Files: FileFetcherConfig{Enabled: true}, 921 InMemoryCache: InMemoryCache{ 922 Type: "none", 923 }, 924 }, 925 CategoryMapping: StoredRequests{ 926 Files: FileFetcherConfig{Enabled: true}, 927 }, 928 Accounts: StoredRequests{ 929 Files: FileFetcherConfig{Enabled: true}, 930 InMemoryCache: InMemoryCache{Type: "none"}, 931 }, 932 AccountDefaults: Account{ 933 PriceFloors: AccountPriceFloors{ 934 Fetcher: AccountFloorFetch{ 935 Timeout: 100, 936 Period: 300, 937 MaxAge: 600, 938 }, 939 }, 940 }, 941 } 942 943 v := viper.New() 944 v.Set("gdpr.default_value", "0") 945 946 resolvedStoredRequestsConfig(&cfg) 947 err := cfg.validate(v) 948 assert.Nil(t, err, "OpenRTB filesystem config should work. %v", err) 949 } 950 951 func TestMigrateConfigFromEnv(t *testing.T) { 952 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_ENDPOINT"); ok { 953 defer os.Setenv("PBS_ADAPTERS_BIDDER1_ENDPOINT", oldval) 954 } else { 955 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_ENDPOINT") 956 } 957 958 os.Setenv("PBS_ADAPTERS_BIDDER1_ENDPOINT", "http://bidder1_override.com") 959 cfg, _ := newDefaultConfig(t) 960 cmpStrings(t, "adapters.bidder1.endpoint", "http://bidder1_override.com", cfg.BidderInfos["bidder1"].Endpoint) 961 } 962 963 func TestUserSyncFromEnv(t *testing.T) { 964 truePtr := true 965 966 // setup env vars for testing 967 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL"); ok { 968 defer os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL", oldval) 969 } else { 970 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL") 971 } 972 973 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_USER_MACRO"); ok { 974 defer os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_USER_MACRO", oldval) 975 } else { 976 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_USER_MACRO") 977 } 978 979 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_USERSYNC_SUPPORT_CORS"); ok { 980 defer os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_SUPPORT_CORS", oldval) 981 } else { 982 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_USERSYNC_SUPPORT_CORS") 983 } 984 985 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER2_USERSYNC_IFRAME_URL"); ok { 986 defer os.Setenv("PBS_ADAPTERS_BIDDER2_USERSYNC_IFRAME_URL", oldval) 987 } else { 988 defer os.Unsetenv("PBS_ADAPTERS_BIDDER2_USERSYNC_IFRAME_URL") 989 } 990 991 // set new 992 os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL", "http://some.url/sync?redirect={{.RedirectURL}}") 993 os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_USER_MACRO", "[UID]") 994 os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_SUPPORT_CORS", "true") 995 os.Setenv("PBS_ADAPTERS_BIDDER2_USERSYNC_IFRAME_URL", "http://somedifferent.url/sync?redirect={{.RedirectURL}}") 996 997 cfg, _ := newDefaultConfig(t) 998 999 assert.Equal(t, "http://some.url/sync?redirect={{.RedirectURL}}", cfg.BidderInfos["bidder1"].Syncer.Redirect.URL) 1000 assert.Equal(t, "[UID]", cfg.BidderInfos["bidder1"].Syncer.Redirect.UserMacro) 1001 assert.Nil(t, cfg.BidderInfos["bidder1"].Syncer.IFrame) 1002 assert.Equal(t, &truePtr, cfg.BidderInfos["bidder1"].Syncer.SupportCORS) 1003 1004 assert.Equal(t, "http://somedifferent.url/sync?redirect={{.RedirectURL}}", cfg.BidderInfos["bidder2"].Syncer.IFrame.URL) 1005 assert.Nil(t, cfg.BidderInfos["bidder2"].Syncer.Redirect) 1006 assert.Nil(t, cfg.BidderInfos["bidder2"].Syncer.SupportCORS) 1007 } 1008 1009 func TestBidderInfoFromEnv(t *testing.T) { 1010 // setup env vars for testing 1011 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_DISABLED"); ok { 1012 defer os.Setenv("PBS_ADAPTERS_BIDDER1_DISABLED", oldval) 1013 } else { 1014 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_DISABLED") 1015 } 1016 1017 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_ENDPOINT"); ok { 1018 defer os.Setenv("PBS_ADAPTERS_BIDDER1_ENDPOINT", oldval) 1019 } else { 1020 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_ENDPOINT") 1021 } 1022 1023 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_EXTRA_INFO"); ok { 1024 defer os.Setenv("PBS_ADAPTERS_BIDDER1_EXTRA_INFO", oldval) 1025 } else { 1026 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_EXTRA_INFO") 1027 } 1028 1029 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_DEBUG_ALLOW"); ok { 1030 defer os.Setenv("PBS_ADAPTERS_BIDDER1_DEBUG_ALLOW", oldval) 1031 } else { 1032 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_DEBUG_ALLOW") 1033 } 1034 1035 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_GVLVENDORID"); ok { 1036 defer os.Setenv("PBS_ADAPTERS_BIDDER1_GVLVENDORID", oldval) 1037 } else { 1038 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_GVLVENDORID") 1039 } 1040 1041 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_EXPERIMENT_ADSCERT_ENABLED"); ok { 1042 defer os.Setenv("PBS_ADAPTERS_BIDDER1_EXPERIMENT_ADSCERT_ENABLED", oldval) 1043 } else { 1044 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_EXPERIMENT_ADSCERT_ENABLED") 1045 } 1046 1047 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_XAPI_USERNAME"); ok { 1048 defer os.Setenv("PBS_ADAPTERS_BIDDER1_XAPI_USERNAME", oldval) 1049 } else { 1050 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_XAPI_USERNAME") 1051 } 1052 1053 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL"); ok { 1054 defer os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL", oldval) 1055 } else { 1056 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL") 1057 } 1058 if oldval, ok := os.LookupEnv("PBS_ADAPTERS_BIDDER1_OPENRTB_VERSION"); ok { 1059 defer os.Setenv("PBS_ADAPTERS_BIDDER1_OPENRTB_VERSION", oldval) 1060 } else { 1061 defer os.Unsetenv("PBS_ADAPTERS_BIDDER1_OPENRTB_VERSION") 1062 } 1063 1064 // set new 1065 os.Setenv("PBS_ADAPTERS_BIDDER1_DISABLED", "true") 1066 os.Setenv("PBS_ADAPTERS_BIDDER1_ENDPOINT", "http://some.url/override") 1067 os.Setenv("PBS_ADAPTERS_BIDDER1_EXTRA_INFO", `{"extrainfo": true}`) 1068 os.Setenv("PBS_ADAPTERS_BIDDER1_DEBUG_ALLOW", "true") 1069 os.Setenv("PBS_ADAPTERS_BIDDER1_GVLVENDORID", "42") 1070 os.Setenv("PBS_ADAPTERS_BIDDER1_EXPERIMENT_ADSCERT_ENABLED", "true") 1071 os.Setenv("PBS_ADAPTERS_BIDDER1_XAPI_USERNAME", "username_override") 1072 os.Setenv("PBS_ADAPTERS_BIDDER1_USERSYNC_REDIRECT_URL", "http://some.url/sync?redirect={{.RedirectURL}}") 1073 os.Setenv("PBS_ADAPTERS_BIDDER1_OPENRTB_VERSION", "2.6") 1074 1075 cfg, _ := newDefaultConfig(t) 1076 1077 assert.Equal(t, true, cfg.BidderInfos["bidder1"].Disabled) 1078 assert.Equal(t, "http://some.url/override", cfg.BidderInfos["bidder1"].Endpoint) 1079 assert.Equal(t, `{"extrainfo": true}`, cfg.BidderInfos["bidder1"].ExtraAdapterInfo) 1080 1081 assert.Equal(t, true, cfg.BidderInfos["bidder1"].Debug.Allow) 1082 assert.Equal(t, uint16(42), cfg.BidderInfos["bidder1"].GVLVendorID) 1083 1084 assert.Equal(t, true, cfg.BidderInfos["bidder1"].Experiment.AdsCert.Enabled) 1085 assert.Equal(t, "username_override", cfg.BidderInfos["bidder1"].XAPI.Username) 1086 1087 assert.Equal(t, "2.6", cfg.BidderInfos["bidder1"].OpenRTB.Version) 1088 } 1089 1090 func TestIsConfigInfoPresent(t *testing.T) { 1091 configPrefix1Field2Only := []byte(` 1092 prefix1: 1093 field2: "value2" 1094 `) 1095 configPrefix1Field4Only := []byte(` 1096 prefix1: 1097 field4: "value4" 1098 `) 1099 configPrefix1Field2AndField3 := []byte(` 1100 prefix1: 1101 field2: "value2" 1102 field3: "value3" 1103 `) 1104 1105 tests := []struct { 1106 description string 1107 config []byte 1108 keyPrefix string 1109 fields []string 1110 wantResult bool 1111 }{ 1112 { 1113 description: "config is nil", 1114 config: nil, 1115 keyPrefix: "prefix1", 1116 fields: []string{"field1", "field2", "field3"}, 1117 wantResult: false, 1118 }, 1119 { 1120 description: "config is empty", 1121 config: []byte{}, 1122 keyPrefix: "prefix1", 1123 fields: []string{"field1", "field2", "field3"}, 1124 wantResult: false, 1125 }, 1126 { 1127 description: "present - one field exists in config", 1128 config: configPrefix1Field2Only, 1129 keyPrefix: "prefix1", 1130 fields: []string{"field1", "field2", "field3"}, 1131 wantResult: true, 1132 }, 1133 { 1134 description: "present - many fields exist in config", 1135 config: configPrefix1Field2AndField3, 1136 keyPrefix: "prefix1", 1137 fields: []string{"field1", "field2", "field3"}, 1138 wantResult: true, 1139 }, 1140 { 1141 description: "not present - field not found", 1142 config: configPrefix1Field4Only, 1143 keyPrefix: "prefix1", 1144 fields: []string{"field1", "field2", "field3"}, 1145 wantResult: false, 1146 }, 1147 { 1148 description: "not present - field exists but with a different prefix", 1149 config: configPrefix1Field2Only, 1150 keyPrefix: "prefix2", 1151 fields: []string{"field1", "field2", "field3"}, 1152 wantResult: false, 1153 }, 1154 { 1155 description: "not present - fields is nil", 1156 config: configPrefix1Field2Only, 1157 keyPrefix: "prefix1", 1158 fields: nil, 1159 wantResult: false, 1160 }, 1161 { 1162 description: "not present - fields is empty", 1163 config: configPrefix1Field2Only, 1164 keyPrefix: "prefix1", 1165 fields: []string{}, 1166 wantResult: false, 1167 }, 1168 } 1169 1170 for _, tt := range tests { 1171 v := viper.New() 1172 v.SetConfigType("yaml") 1173 v.ReadConfig(bytes.NewBuffer(tt.config)) 1174 1175 result := isConfigInfoPresent(v, tt.keyPrefix, tt.fields) 1176 assert.Equal(t, tt.wantResult, result, tt.description) 1177 } 1178 } 1179 1180 func TestNegativeOrZeroStoredRequestsTimeout(t *testing.T) { 1181 cfg, v := newDefaultConfig(t) 1182 1183 cfg.StoredRequestsTimeout = -1 1184 assertOneError(t, cfg.validate(v), "cfg.stored_requests_timeout_ms must be > 0. Got -1") 1185 1186 cfg.StoredRequestsTimeout = 0 1187 assertOneError(t, cfg.validate(v), "cfg.stored_requests_timeout_ms must be > 0. Got 0") 1188 } 1189 1190 func TestNegativeRequestSize(t *testing.T) { 1191 cfg, v := newDefaultConfig(t) 1192 cfg.MaxRequestSize = -1 1193 assertOneError(t, cfg.validate(v), "cfg.max_request_size must be >= 0. Got -1") 1194 } 1195 1196 func TestNegativePrometheusTimeout(t *testing.T) { 1197 cfg, v := newDefaultConfig(t) 1198 cfg.Metrics.Prometheus.Port = 8001 1199 cfg.Metrics.Prometheus.TimeoutMillisRaw = 0 1200 assertOneError(t, cfg.validate(v), "metrics.prometheus.timeout_ms must be positive if metrics.prometheus.port is defined. Got timeout=0 and port=8001") 1201 } 1202 1203 func TestInvalidHostVendorID(t *testing.T) { 1204 tests := []struct { 1205 description string 1206 vendorID int 1207 wantErrorMsg string 1208 }{ 1209 { 1210 description: "Negative GDPR.HostVendorID", 1211 vendorID: -1, 1212 wantErrorMsg: "gdpr.host_vendor_id must be in the range [0, 65535]. Got -1", 1213 }, 1214 { 1215 description: "Overflowed GDPR.HostVendorID", 1216 vendorID: (0xffff) + 1, 1217 wantErrorMsg: "gdpr.host_vendor_id must be in the range [0, 65535]. Got 65536", 1218 }, 1219 } 1220 1221 for _, tt := range tests { 1222 cfg, v := newDefaultConfig(t) 1223 cfg.GDPR.HostVendorID = tt.vendorID 1224 errs := cfg.validate(v) 1225 1226 assert.Equal(t, 1, len(errs), tt.description) 1227 assert.EqualError(t, errs[0], tt.wantErrorMsg, tt.description) 1228 } 1229 } 1230 1231 func TestInvalidAMPException(t *testing.T) { 1232 cfg, v := newDefaultConfig(t) 1233 cfg.GDPR.AMPException = true 1234 assertOneError(t, cfg.validate(v), "gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)") 1235 } 1236 1237 func TestInvalidGDPRDefaultValue(t *testing.T) { 1238 cfg, v := newDefaultConfig(t) 1239 cfg.GDPR.DefaultValue = "2" 1240 assertOneError(t, cfg.validate(v), "gdpr.default_value must be 0 or 1") 1241 } 1242 1243 func TestMissingGDPRDefaultValue(t *testing.T) { 1244 v := viper.New() 1245 1246 cfg, _ := newDefaultConfig(t) 1247 assertOneError(t, cfg.validate(v), "gdpr.default_value is required and must be specified") 1248 } 1249 1250 func TestInvalidEnforceAlgo(t *testing.T) { 1251 cfg, v := newDefaultConfig(t) 1252 cfg.GDPR.TCF2.Purpose1.EnforceAlgo = "" 1253 cfg.GDPR.TCF2.Purpose2.EnforceAlgo = TCF2EnforceAlgoFull 1254 cfg.GDPR.TCF2.Purpose3.EnforceAlgo = TCF2EnforceAlgoBasic 1255 cfg.GDPR.TCF2.Purpose4.EnforceAlgo = TCF2EnforceAlgoFull 1256 cfg.GDPR.TCF2.Purpose5.EnforceAlgo = "invalid1" 1257 cfg.GDPR.TCF2.Purpose6.EnforceAlgo = "invalid2" 1258 cfg.GDPR.TCF2.Purpose7.EnforceAlgo = TCF2EnforceAlgoFull 1259 cfg.GDPR.TCF2.Purpose8.EnforceAlgo = TCF2EnforceAlgoBasic 1260 cfg.GDPR.TCF2.Purpose9.EnforceAlgo = TCF2EnforceAlgoFull 1261 cfg.GDPR.TCF2.Purpose10.EnforceAlgo = "invalid3" 1262 1263 errs := cfg.validate(v) 1264 1265 expectedErrs := []error{ 1266 errors.New("gdpr.tcf2.purpose1.enforce_algo must be \"basic\" or \"full\". Got "), 1267 errors.New("gdpr.tcf2.purpose5.enforce_algo must be \"basic\" or \"full\". Got invalid1"), 1268 errors.New("gdpr.tcf2.purpose6.enforce_algo must be \"basic\" or \"full\". Got invalid2"), 1269 errors.New("gdpr.tcf2.purpose10.enforce_algo must be \"basic\" or \"full\". Got invalid3"), 1270 } 1271 assert.ElementsMatch(t, errs, expectedErrs, "gdpr.tcf2.purposeX.enforce_algo should prevent invalid values but it doesn't") 1272 } 1273 1274 func TestNegativeCurrencyConverterFetchInterval(t *testing.T) { 1275 v := viper.New() 1276 v.Set("gdpr.default_value", "0") 1277 1278 cfg := Configuration{ 1279 CurrencyConverter: CurrencyConverter{ 1280 FetchIntervalSeconds: -1, 1281 }, 1282 } 1283 err := cfg.validate(v) 1284 assert.NotNil(t, err, "cfg.currency_converter.fetch_interval_seconds should prevent negative values, but it doesn't") 1285 } 1286 1287 func TestOverflowedCurrencyConverterFetchInterval(t *testing.T) { 1288 v := viper.New() 1289 v.Set("gdpr.default_value", "0") 1290 1291 cfg := Configuration{ 1292 CurrencyConverter: CurrencyConverter{ 1293 FetchIntervalSeconds: (0xffff) + 1, 1294 }, 1295 } 1296 err := cfg.validate(v) 1297 assert.NotNil(t, err, "cfg.currency_converter.fetch_interval_seconds prevent values over %d, but it doesn't", 0xffff) 1298 } 1299 1300 func TestLimitTimeout(t *testing.T) { 1301 doTimeoutTest(t, 10, 15, 10, 0) 1302 doTimeoutTest(t, 10, 0, 10, 0) 1303 doTimeoutTest(t, 5, 5, 10, 0) 1304 doTimeoutTest(t, 15, 15, 0, 0) 1305 doTimeoutTest(t, 15, 0, 20, 15) 1306 } 1307 1308 func TestCookieSizeError(t *testing.T) { 1309 testCases := []struct { 1310 description string 1311 cookieSize int 1312 expectError bool 1313 }{ 1314 {"MIN_COOKIE_SIZE_BYTES + 1", MIN_COOKIE_SIZE_BYTES + 1, false}, 1315 {"MIN_COOKIE_SIZE_BYTES", MIN_COOKIE_SIZE_BYTES, false}, 1316 {"MIN_COOKIE_SIZE_BYTES - 1", MIN_COOKIE_SIZE_BYTES - 1, true}, 1317 {"Zero", 0, false}, 1318 {"Negative", -100, true}, 1319 } 1320 1321 for _, test := range testCases { 1322 resultErr := isValidCookieSize(test.cookieSize) 1323 1324 if test.expectError { 1325 assert.Error(t, resultErr, test.description) 1326 } else { 1327 assert.NoError(t, resultErr, test.description) 1328 } 1329 } 1330 } 1331 1332 func TestNewCallsRequestValidation(t *testing.T) { 1333 testCases := []struct { 1334 description string 1335 privateIPNetworks string 1336 expectedError string 1337 expectedIPs []net.IPNet 1338 }{ 1339 { 1340 description: "Valid", 1341 privateIPNetworks: `["1.1.1.0/24"]`, 1342 expectedIPs: []net.IPNet{{IP: net.IP{1, 1, 1, 0}, Mask: net.CIDRMask(24, 32)}}, 1343 }, 1344 { 1345 description: "Invalid", 1346 privateIPNetworks: `["1"]`, 1347 expectedError: "Invalid private IPv4 networks: '1'", 1348 }, 1349 } 1350 1351 for _, test := range testCases { 1352 v := viper.New() 1353 SetupViper(v, "", bidderInfos) 1354 v.Set("gdpr.default_value", "0") 1355 v.SetConfigType("yaml") 1356 v.ReadConfig(bytes.NewBuffer([]byte( 1357 `request_validation: 1358 ipv4_private_networks: ` + test.privateIPNetworks))) 1359 1360 result, resultErr := New(v, bidderInfos, mockNormalizeBidderName) 1361 1362 if test.expectedError == "" { 1363 assert.NoError(t, resultErr, test.description+":err") 1364 assert.ElementsMatch(t, test.expectedIPs, result.RequestValidation.IPv4PrivateNetworksParsed, test.description+":parsed") 1365 } else { 1366 assert.Error(t, resultErr, test.description+":err") 1367 } 1368 } 1369 } 1370 1371 func TestValidateDebug(t *testing.T) { 1372 cfg, v := newDefaultConfig(t) 1373 cfg.Debug.TimeoutNotification.SamplingRate = 1.1 1374 1375 err := cfg.validate(v) 1376 assert.NotNil(t, err, "cfg.debug.timeout_notification.sampling_rate should not be allowed to be greater than 1.0, but it was allowed") 1377 } 1378 1379 func TestValidateAccountsConfigRestrictions(t *testing.T) { 1380 cfg, v := newDefaultConfig(t) 1381 cfg.Accounts.Files.Enabled = true 1382 cfg.Accounts.HTTP.Endpoint = "http://localhost" 1383 cfg.Accounts.Database.ConnectionInfo.Database = "accounts" 1384 1385 errs := cfg.validate(v) 1386 assert.Len(t, errs, 1) 1387 assert.Contains(t, errs, errors.New("accounts.database: retrieving accounts via database not available, use accounts.files")) 1388 } 1389 1390 func newDefaultConfig(t *testing.T) (*Configuration, *viper.Viper) { 1391 v := viper.New() 1392 SetupViper(v, "", bidderInfos) 1393 v.Set("gdpr.default_value", "0") 1394 v.SetConfigType("yaml") 1395 cfg, err := New(v, bidderInfos, mockNormalizeBidderName) 1396 assert.NoError(t, err, "Setting up config should work but it doesn't") 1397 return cfg, v 1398 } 1399 1400 func assertOneError(t *testing.T, errs []error, message string) { 1401 if !assert.Len(t, errs, 1) { 1402 return 1403 } 1404 assert.EqualError(t, errs[0], message) 1405 } 1406 1407 func doTimeoutTest(t *testing.T, expected int, requested int, max uint64, def uint64) { 1408 t.Helper() 1409 cfg := AuctionTimeouts{ 1410 Default: def, 1411 Max: max, 1412 } 1413 expectedDuration := time.Duration(expected) * time.Millisecond 1414 limited := cfg.LimitAuctionTimeout(time.Duration(requested) * time.Millisecond) 1415 assert.Equal(t, limited, expectedDuration, "Expected %dms timeout, got %dms", expectedDuration, limited/time.Millisecond) 1416 } 1417 1418 func TestSpecialFeature1VendorExceptionMap(t *testing.T) { 1419 baseConfig := []byte(` 1420 gdpr: 1421 default_value: 0 1422 tcf2: 1423 special_feature1: 1424 vendor_exceptions: `) 1425 1426 tests := []struct { 1427 description string 1428 configVendorExceptions []byte 1429 wantVendorExceptions []openrtb_ext.BidderName 1430 wantVendorExceptionsMap map[openrtb_ext.BidderName]struct{} 1431 }{ 1432 { 1433 description: "nil vendor exceptions", 1434 configVendorExceptions: []byte(`null`), 1435 wantVendorExceptions: []openrtb_ext.BidderName{}, 1436 wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{}, 1437 }, 1438 { 1439 description: "no vendor exceptions", 1440 configVendorExceptions: []byte(`[]`), 1441 wantVendorExceptions: []openrtb_ext.BidderName{}, 1442 wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{}, 1443 }, 1444 { 1445 description: "one vendor exception", 1446 configVendorExceptions: []byte(`["vendor1"]`), 1447 wantVendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("vendor1")}, 1448 wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("vendor1"): {}}, 1449 }, 1450 { 1451 description: "many exceptions", 1452 configVendorExceptions: []byte(`["vendor1","vendor2"]`), 1453 wantVendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("vendor1"), openrtb_ext.BidderName("vendor2")}, 1454 wantVendorExceptionsMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("vendor1"): {}, openrtb_ext.BidderName("vendor2"): {}}, 1455 }, 1456 } 1457 1458 for _, tt := range tests { 1459 config := append(baseConfig, tt.configVendorExceptions...) 1460 1461 v := viper.New() 1462 SetupViper(v, "", bidderInfos) 1463 v.SetConfigType("yaml") 1464 v.ReadConfig(bytes.NewBuffer(config)) 1465 cfg, err := New(v, bidderInfos, mockNormalizeBidderName) 1466 assert.NoError(t, err, "Setting up config error", tt.description) 1467 1468 assert.Equal(t, tt.wantVendorExceptions, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptions, tt.description) 1469 assert.Equal(t, tt.wantVendorExceptionsMap, cfg.GDPR.TCF2.SpecialFeature1.VendorExceptionMap, tt.description) 1470 } 1471 } 1472 1473 func TestSetConfigBidderInfoNillableFields(t *testing.T) { 1474 falseValue := false 1475 trueValue := true 1476 1477 bidder1ConfigFalses := []byte(` 1478 adapters: 1479 bidder1: 1480 disabled: false 1481 modifyingVastXmlAllowed: false`) 1482 bidder1ConfigTrues := []byte(` 1483 adapters: 1484 bidder1: 1485 disabled: true 1486 modifyingVastXmlAllowed: true`) 1487 bidder1ConfigNils := []byte(` 1488 adapters: 1489 bidder1: 1490 disabled: null 1491 modifyingVastXmlAllowed: null`) 1492 bidder1Bidder2ConfigMixed := []byte(` 1493 adapters: 1494 bidder1: 1495 disabled: true 1496 modifyingVastXmlAllowed: false 1497 bidder2: 1498 disabled: false 1499 modifyingVastXmlAllowed: true`) 1500 1501 tests := []struct { 1502 name string 1503 rawConfig []byte 1504 bidderInfos BidderInfos 1505 expected nillableFieldBidderInfos 1506 expectError bool 1507 }{ 1508 { 1509 name: "viper and bidder infos are nil", 1510 expected: nil, 1511 }, 1512 { 1513 name: "viper is nil", 1514 bidderInfos: map[string]BidderInfo{}, 1515 expected: nil, 1516 }, 1517 { 1518 name: "bidder infos is nil", 1519 rawConfig: []byte{}, 1520 expected: nil, 1521 }, 1522 { 1523 name: "bidder infos is empty", 1524 bidderInfos: map[string]BidderInfo{}, 1525 expected: nil, 1526 }, 1527 { 1528 name: "one: bidder info has nillable fields as false, viper has as nil", 1529 bidderInfos: map[string]BidderInfo{ 1530 "bidder1": {Disabled: false, ModifyingVastXmlAllowed: false}, 1531 }, 1532 rawConfig: bidder1ConfigNils, 1533 expected: nillableFieldBidderInfos{ 1534 "bidder1": nillableFieldBidderInfo{ 1535 nillableFields: bidderInfoNillableFields{ 1536 Disabled: nil, 1537 ModifyingVastXmlAllowed: nil, 1538 }, 1539 bidderInfo: BidderInfo{Disabled: false, ModifyingVastXmlAllowed: false}, 1540 }, 1541 }, 1542 }, 1543 { 1544 name: "one: bidder info has nillable fields as false, viper has as false", 1545 bidderInfos: map[string]BidderInfo{ 1546 "bidder1": {Disabled: false, ModifyingVastXmlAllowed: false}, 1547 }, 1548 rawConfig: bidder1ConfigFalses, 1549 expected: nillableFieldBidderInfos{ 1550 "bidder1": nillableFieldBidderInfo{ 1551 nillableFields: bidderInfoNillableFields{ 1552 Disabled: &falseValue, 1553 ModifyingVastXmlAllowed: &falseValue, 1554 }, 1555 bidderInfo: BidderInfo{Disabled: false, ModifyingVastXmlAllowed: false}, 1556 }, 1557 }, 1558 }, 1559 { 1560 name: "one: bidder info has nillable fields as false, viper has as true", 1561 bidderInfos: map[string]BidderInfo{ 1562 "bidder1": {Disabled: false, ModifyingVastXmlAllowed: false}, 1563 }, 1564 rawConfig: bidder1ConfigTrues, 1565 expected: nillableFieldBidderInfos{ 1566 "bidder1": nillableFieldBidderInfo{ 1567 nillableFields: bidderInfoNillableFields{ 1568 Disabled: &trueValue, 1569 ModifyingVastXmlAllowed: &trueValue, 1570 }, 1571 bidderInfo: BidderInfo{Disabled: false, ModifyingVastXmlAllowed: false}, 1572 }, 1573 }, 1574 }, 1575 { 1576 name: "many with extra info: bidder infos have nillable fields as false and true, viper has as true and false", 1577 bidderInfos: map[string]BidderInfo{ 1578 "bidder1": {Disabled: false, ModifyingVastXmlAllowed: true, Endpoint: "endpoint a"}, 1579 "bidder2": {Disabled: true, ModifyingVastXmlAllowed: false, Endpoint: "endpoint b"}, 1580 }, 1581 rawConfig: bidder1Bidder2ConfigMixed, 1582 expected: nillableFieldBidderInfos{ 1583 "bidder1": nillableFieldBidderInfo{ 1584 nillableFields: bidderInfoNillableFields{ 1585 Disabled: &trueValue, 1586 ModifyingVastXmlAllowed: &falseValue, 1587 }, 1588 bidderInfo: BidderInfo{Disabled: false, ModifyingVastXmlAllowed: true, Endpoint: "endpoint a"}, 1589 }, 1590 "bidder2": nillableFieldBidderInfo{ 1591 nillableFields: bidderInfoNillableFields{ 1592 Disabled: &falseValue, 1593 ModifyingVastXmlAllowed: &trueValue, 1594 }, 1595 bidderInfo: BidderInfo{Disabled: true, ModifyingVastXmlAllowed: false, Endpoint: "endpoint b"}, 1596 }, 1597 }, 1598 }, 1599 } 1600 1601 for _, tt := range tests { 1602 t.Run(tt.name, func(t *testing.T) { 1603 v := viper.New() 1604 v.SetConfigType("yaml") 1605 for bidderName := range tt.bidderInfos { 1606 setBidderDefaults(v, strings.ToLower(bidderName)) 1607 } 1608 v.ReadConfig(bytes.NewBuffer(tt.rawConfig)) 1609 1610 result, err := setConfigBidderInfoNillableFields(v, tt.bidderInfos) 1611 1612 assert.Equal(t, tt.expected, result) 1613 if tt.expectError { 1614 assert.NotNil(t, err) 1615 } else { 1616 assert.Nil(t, err) 1617 } 1618 }) 1619 } 1620 } 1621 1622 func TestTCF2PurposeEnforced(t *testing.T) { 1623 tests := []struct { 1624 description string 1625 givePurposeConfigNil bool 1626 givePurpose1Enforced bool 1627 givePurpose2Enforced bool 1628 givePurpose consentconstants.Purpose 1629 wantEnforced bool 1630 }{ 1631 { 1632 description: "Purpose config is nil", 1633 givePurposeConfigNil: true, 1634 givePurpose: 1, 1635 wantEnforced: false, 1636 }, 1637 { 1638 description: "Purpose 1 Enforced set to true", 1639 givePurpose1Enforced: true, 1640 givePurpose: 1, 1641 wantEnforced: true, 1642 }, 1643 { 1644 description: "Purpose 1 Enforced set to false", 1645 givePurpose1Enforced: false, 1646 givePurpose: 1, 1647 wantEnforced: false, 1648 }, 1649 { 1650 description: "Purpose 2 Enforced set to true", 1651 givePurpose2Enforced: true, 1652 givePurpose: 2, 1653 wantEnforced: true, 1654 }, 1655 } 1656 1657 for _, tt := range tests { 1658 tcf2 := TCF2{} 1659 1660 if !tt.givePurposeConfigNil { 1661 tcf2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 1662 1: { 1663 EnforcePurpose: tt.givePurpose1Enforced, 1664 }, 1665 2: { 1666 EnforcePurpose: tt.givePurpose2Enforced, 1667 }, 1668 } 1669 } 1670 1671 value := tcf2.PurposeEnforced(tt.givePurpose) 1672 1673 assert.Equal(t, tt.wantEnforced, value, tt.description) 1674 } 1675 } 1676 1677 func TestTCF2PurposeEnforcementAlgo(t *testing.T) { 1678 tests := []struct { 1679 description string 1680 givePurposeConfigNil bool 1681 givePurpose1Algo TCF2EnforcementAlgo 1682 givePurpose2Algo TCF2EnforcementAlgo 1683 givePurpose consentconstants.Purpose 1684 wantAlgo TCF2EnforcementAlgo 1685 }{ 1686 { 1687 description: "Purpose config is nil", 1688 givePurposeConfigNil: true, 1689 givePurpose: 1, 1690 wantAlgo: TCF2FullEnforcement, 1691 }, 1692 { 1693 description: "Purpose 1 enforcement algo set to basic", 1694 givePurpose1Algo: TCF2BasicEnforcement, 1695 givePurpose: 1, 1696 wantAlgo: TCF2BasicEnforcement, 1697 }, 1698 { 1699 description: "Purpose 1 enforcement algo set to full", 1700 givePurpose1Algo: TCF2FullEnforcement, 1701 givePurpose: 1, 1702 wantAlgo: TCF2FullEnforcement, 1703 }, 1704 { 1705 description: "Purpose 2 Enforcement algo set to basic", 1706 givePurpose2Algo: TCF2BasicEnforcement, 1707 givePurpose: 2, 1708 wantAlgo: TCF2BasicEnforcement, 1709 }, 1710 } 1711 1712 for _, tt := range tests { 1713 tcf2 := TCF2{} 1714 1715 if !tt.givePurposeConfigNil { 1716 tcf2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 1717 1: { 1718 EnforceAlgoID: tt.givePurpose1Algo, 1719 }, 1720 2: { 1721 EnforceAlgoID: tt.givePurpose2Algo, 1722 }, 1723 } 1724 } 1725 1726 value := tcf2.PurposeEnforcementAlgo(tt.givePurpose) 1727 1728 assert.Equal(t, tt.wantAlgo, value, tt.description) 1729 } 1730 } 1731 1732 func TestTCF2PurposeEnforcingVendors(t *testing.T) { 1733 tests := []struct { 1734 description string 1735 givePurposeConfigNil bool 1736 givePurpose1Enforcing bool 1737 givePurpose2Enforcing bool 1738 givePurpose consentconstants.Purpose 1739 wantEnforcing bool 1740 }{ 1741 { 1742 description: "Purpose config is nil", 1743 givePurposeConfigNil: true, 1744 givePurpose: 1, 1745 wantEnforcing: false, 1746 }, 1747 { 1748 description: "Purpose 1 Enforcing set to true", 1749 givePurpose1Enforcing: true, 1750 givePurpose: 1, 1751 wantEnforcing: true, 1752 }, 1753 { 1754 description: "Purpose 1 Enforcing set to false", 1755 givePurpose1Enforcing: false, 1756 givePurpose: 1, 1757 wantEnforcing: false, 1758 }, 1759 { 1760 description: "Purpose 2 Enforcing set to true", 1761 givePurpose2Enforcing: true, 1762 givePurpose: 2, 1763 wantEnforcing: true, 1764 }, 1765 } 1766 1767 for _, tt := range tests { 1768 tcf2 := TCF2{} 1769 1770 if !tt.givePurposeConfigNil { 1771 tcf2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 1772 1: { 1773 EnforceVendors: tt.givePurpose1Enforcing, 1774 }, 1775 2: { 1776 EnforceVendors: tt.givePurpose2Enforcing, 1777 }, 1778 } 1779 } 1780 1781 value := tcf2.PurposeEnforcingVendors(tt.givePurpose) 1782 1783 assert.Equal(t, tt.wantEnforcing, value, tt.description) 1784 } 1785 } 1786 1787 func TestTCF2PurposeVendorExceptions(t *testing.T) { 1788 tests := []struct { 1789 description string 1790 givePurposeConfigNil bool 1791 givePurpose1ExceptionMap map[string]struct{} 1792 givePurpose2ExceptionMap map[string]struct{} 1793 givePurpose consentconstants.Purpose 1794 wantExceptionMap map[string]struct{} 1795 }{ 1796 { 1797 description: "Purpose config is nil", 1798 givePurposeConfigNil: true, 1799 givePurpose: 1, 1800 wantExceptionMap: map[string]struct{}{}, 1801 }, 1802 { 1803 description: "Nil - exception map not defined for purpose", 1804 givePurpose: 1, 1805 wantExceptionMap: map[string]struct{}{}, 1806 }, 1807 { 1808 description: "Empty - exception map empty for purpose", 1809 givePurpose: 1, 1810 givePurpose1ExceptionMap: map[string]struct{}{}, 1811 wantExceptionMap: map[string]struct{}{}, 1812 }, 1813 { 1814 description: "Nonempty - exception map with multiple entries for purpose", 1815 givePurpose: 1, 1816 givePurpose1ExceptionMap: map[string]struct{}{"rubicon": {}, "appnexus": {}, "index": {}}, 1817 wantExceptionMap: map[string]struct{}{"rubicon": {}, "appnexus": {}, "index": {}}, 1818 }, 1819 { 1820 description: "Nonempty - exception map with multiple entries for different purpose", 1821 givePurpose: 2, 1822 givePurpose1ExceptionMap: map[string]struct{}{"rubicon": {}, "appnexus": {}, "index": {}}, 1823 givePurpose2ExceptionMap: map[string]struct{}{"rubicon": {}, "appnexus": {}, "openx": {}}, 1824 wantExceptionMap: map[string]struct{}{"rubicon": {}, "appnexus": {}, "openx": {}}, 1825 }, 1826 } 1827 1828 for _, tt := range tests { 1829 tcf2 := TCF2{} 1830 1831 if !tt.givePurposeConfigNil { 1832 tcf2.PurposeConfigs = map[consentconstants.Purpose]*TCF2Purpose{ 1833 1: { 1834 VendorExceptionMap: tt.givePurpose1ExceptionMap, 1835 }, 1836 2: { 1837 VendorExceptionMap: tt.givePurpose2ExceptionMap, 1838 }, 1839 } 1840 } 1841 1842 value := tcf2.PurposeVendorExceptions(tt.givePurpose) 1843 1844 assert.Equal(t, tt.wantExceptionMap, value, tt.description) 1845 } 1846 } 1847 1848 func TestTCF2FeatureOneVendorException(t *testing.T) { 1849 tests := []struct { 1850 description string 1851 giveExceptionMap map[openrtb_ext.BidderName]struct{} 1852 giveBidder openrtb_ext.BidderName 1853 wantIsVendorException bool 1854 }{ 1855 { 1856 description: "Nil - exception map not defined", 1857 giveBidder: "appnexus", 1858 wantIsVendorException: false, 1859 }, 1860 { 1861 description: "Empty - exception map empty", 1862 giveExceptionMap: map[openrtb_ext.BidderName]struct{}{}, 1863 giveBidder: "appnexus", 1864 wantIsVendorException: false, 1865 }, 1866 { 1867 description: "One - bidder found in exception map containing one entry", 1868 giveExceptionMap: map[openrtb_ext.BidderName]struct{}{"appnexus": {}}, 1869 giveBidder: "appnexus", 1870 wantIsVendorException: true, 1871 }, 1872 { 1873 description: "Many - bidder found in exception map containing multiple entries", 1874 giveExceptionMap: map[openrtb_ext.BidderName]struct{}{"rubicon": {}, "appnexus": {}, "index": {}}, 1875 giveBidder: "appnexus", 1876 wantIsVendorException: true, 1877 }, 1878 { 1879 description: "Many - bidder not found in exception map containing multiple entries", 1880 giveExceptionMap: map[openrtb_ext.BidderName]struct{}{"rubicon": {}, "appnexus": {}, "index": {}}, 1881 giveBidder: "openx", 1882 wantIsVendorException: false, 1883 }, 1884 } 1885 1886 for _, tt := range tests { 1887 tcf2 := TCF2{ 1888 SpecialFeature1: TCF2SpecialFeature{ 1889 VendorExceptionMap: tt.giveExceptionMap, 1890 }, 1891 } 1892 1893 value := tcf2.FeatureOneVendorException(tt.giveBidder) 1894 1895 assert.Equal(t, tt.wantIsVendorException, value, tt.description) 1896 } 1897 } 1898 1899 func TestUnpackDSADefault(t *testing.T) { 1900 tests := []struct { 1901 name string 1902 giveDSA *AccountDSA 1903 wantError bool 1904 }{ 1905 { 1906 name: "nil", 1907 giveDSA: nil, 1908 wantError: false, 1909 }, 1910 { 1911 name: "empty", 1912 giveDSA: &AccountDSA{ 1913 Default: "", 1914 }, 1915 wantError: false, 1916 }, 1917 { 1918 name: "empty_json", 1919 giveDSA: &AccountDSA{ 1920 Default: "{}", 1921 }, 1922 wantError: false, 1923 }, 1924 { 1925 name: "well_formed", 1926 giveDSA: &AccountDSA{ 1927 Default: "{\"dsarequired\":3,\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}", 1928 }, 1929 wantError: false, 1930 }, 1931 { 1932 name: "well_formed_with_extra_fields", 1933 giveDSA: &AccountDSA{ 1934 Default: "{\"unmappedkey\":\"unmappedvalue\",\"dsarequired\":3,\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}", 1935 }, 1936 wantError: false, 1937 }, 1938 { 1939 name: "invalid_type", 1940 giveDSA: &AccountDSA{ 1941 Default: "{\"dsarequired\":\"invalid\",\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}", 1942 }, 1943 wantError: true, 1944 }, 1945 { 1946 name: "invalid_malformed_missing_colon", 1947 giveDSA: &AccountDSA{ 1948 Default: "{\"dsarequired\"3,\"pubrender\":1,\"datatopub\":2,\"transparency\":[{\"domain\":\"domain.com\",\"dsaparams\":[1]}]}", 1949 }, 1950 wantError: true, 1951 }, 1952 } 1953 1954 for _, tt := range tests { 1955 t.Run(tt.name, func(t *testing.T) { 1956 err := UnpackDSADefault(tt.giveDSA) 1957 if tt.wantError { 1958 assert.Error(t, err) 1959 } else { 1960 assert.NoError(t, err) 1961 } 1962 }) 1963 } 1964 }