github.com/prebid/prebid-server/v2@v2.18.0/router/router_test.go (about) 1 package router 2 3 import ( 4 "encoding/json" 5 "net/http" 6 "net/http/httptest" 7 "os" 8 "testing" 9 10 jsoniter "github.com/json-iterator/go" 11 "github.com/prebid/prebid-server/v2/config" 12 "github.com/prebid/prebid-server/v2/openrtb_ext" 13 "github.com/prebid/prebid-server/v2/util/jsonutil" 14 15 "github.com/stretchr/testify/assert" 16 ) 17 18 const adapterDirectory = "../adapters" 19 20 type testValidator struct{} 21 22 func TestMain(m *testing.M) { 23 jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{}) 24 os.Exit(m.Run()) 25 } 26 27 func (validator *testValidator) Validate(name openrtb_ext.BidderName, ext json.RawMessage) error { 28 return nil 29 } 30 31 func (validator *testValidator) Schema(name openrtb_ext.BidderName) string { 32 if name == openrtb_ext.BidderAppnexus { 33 return "{\"appnexus\":true}" 34 } else { 35 return "{\"appnexus\":false}" 36 } 37 } 38 39 func ensureHasKey(t *testing.T, data map[string]json.RawMessage, key string) { 40 t.Helper() 41 if _, ok := data[key]; !ok { 42 t.Errorf("Expected map to produce a schema for adapter: %s", key) 43 } 44 } 45 46 func TestNewJsonDirectoryServer(t *testing.T) { 47 defaultAlias := map[string]string{"aliastest": "appnexus"} 48 yamlAlias := map[openrtb_ext.BidderName]openrtb_ext.BidderName{openrtb_ext.BidderName("alias"): openrtb_ext.BidderName("parentAlias")} 49 handler := newJsonDirectoryServer("../static/bidder-params", &testValidator{}, defaultAlias, yamlAlias) 50 recorder := httptest.NewRecorder() 51 request, _ := http.NewRequest("GET", "/whatever", nil) 52 handler(recorder, request, nil) 53 54 var data map[string]json.RawMessage 55 jsonutil.UnmarshalValid(recorder.Body.Bytes(), &data) 56 57 // Make sure that every adapter has a json schema by the same name associated with it. 58 adapterFiles, err := os.ReadDir(adapterDirectory) 59 if err != nil { 60 t.Fatalf("Failed to open the adapters directory: %v", err) 61 } 62 63 for _, adapterFile := range adapterFiles { 64 if adapterFile.IsDir() && adapterFile.Name() != "adapterstest" { 65 ensureHasKey(t, data, adapterFile.Name()) 66 } 67 } 68 69 ensureHasKey(t, data, "aliastest") 70 ensureHasKey(t, data, "alias") 71 } 72 73 func TestCheckSupportedUserSyncEndpoints(t *testing.T) { 74 anyEndpoint := &config.SyncerEndpoint{URL: "anyURL"} 75 76 var testCases = []struct { 77 description string 78 givenBidderInfos config.BidderInfos 79 expectedError string 80 }{ 81 { 82 description: "None", 83 givenBidderInfos: config.BidderInfos{}, 84 expectedError: "", 85 }, 86 { 87 description: "One - No Syncer", 88 givenBidderInfos: config.BidderInfos{ 89 "a": config.BidderInfo{Syncer: nil}, 90 }, 91 expectedError: "", 92 }, 93 { 94 description: "One - Invalid Supported Endpoint", 95 givenBidderInfos: config.BidderInfos{ 96 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"invalid"}}}, 97 }, 98 expectedError: "failed to load bidder info for a, user sync supported endpoint 'invalid' is unrecognized", 99 }, 100 { 101 description: "One - IFrame Supported - Not Specified", 102 givenBidderInfos: config.BidderInfos{ 103 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"iframe"}, IFrame: nil}}, 104 }, 105 expectedError: "", 106 }, 107 { 108 description: "One - IFrame Supported - Specified", 109 givenBidderInfos: config.BidderInfos{ 110 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"iframe"}, IFrame: anyEndpoint}}, 111 }, 112 expectedError: "", 113 }, 114 { 115 description: "One - Redirect Supported - Not Specified", 116 givenBidderInfos: config.BidderInfos{ 117 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"redirect"}, Redirect: nil}}, 118 }, 119 expectedError: "", 120 }, 121 { 122 description: "One - IFrame Supported - Specified", 123 givenBidderInfos: config.BidderInfos{ 124 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"redirect"}, Redirect: anyEndpoint}}, 125 }, 126 expectedError: "", 127 }, 128 { 129 description: "One - IFrame + Redirect Supported - Not Specified", 130 givenBidderInfos: config.BidderInfos{ 131 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"iframe", "redirect"}, IFrame: nil, Redirect: nil}}, 132 }, 133 expectedError: "", 134 }, 135 { 136 description: "One - IFrame + Redirect Supported - Specified", 137 givenBidderInfos: config.BidderInfos{ 138 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"iframe", "redirect"}, IFrame: anyEndpoint, Redirect: anyEndpoint}}, 139 }, 140 expectedError: "", 141 }, 142 { 143 description: "Many - With Invalid Supported Endpoint", 144 givenBidderInfos: config.BidderInfos{ 145 "a": config.BidderInfo{}, 146 "b": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"invalid"}}}, 147 }, 148 expectedError: "failed to load bidder info for b, user sync supported endpoint 'invalid' is unrecognized", 149 }, 150 { 151 description: "Many - Specified + Not Specified", 152 givenBidderInfos: config.BidderInfos{ 153 "a": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"iframe"}, IFrame: anyEndpoint}}, 154 "b": config.BidderInfo{Syncer: &config.Syncer{Supports: []string{"redirect"}, Redirect: nil}}, 155 }, 156 expectedError: "", 157 }, 158 } 159 160 for _, test := range testCases { 161 resultErr := checkSupportedUserSyncEndpoints(test.givenBidderInfos) 162 if test.expectedError == "" { 163 assert.NoError(t, resultErr, test.description) 164 } else { 165 assert.EqualError(t, resultErr, test.expectedError, test.description) 166 } 167 } 168 } 169 170 // Prevents #648 171 func TestCORSSupport(t *testing.T) { 172 const origin = "https://publisher-domain.com" 173 handler := func(w http.ResponseWriter, r *http.Request) {} 174 cors := SupportCORS(http.HandlerFunc(handler)) 175 rr := httptest.NewRecorder() 176 req, err := http.NewRequest("OPTIONS", "http://some-domain.com/openrtb2/auction", nil) 177 req.Header.Set("Access-Control-Request-Method", "POST") 178 req.Header.Set("Access-Control-Request-Headers", "origin") 179 req.Header.Set("Origin", origin) 180 181 if !assert.NoError(t, err) { 182 return 183 } 184 cors.ServeHTTP(rr, req) 185 assert.Equal(t, origin, rr.Header().Get("Access-Control-Allow-Origin")) 186 } 187 188 func TestNoCache(t *testing.T) { 189 nc := NoCache{ 190 Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), 191 } 192 rw := httptest.NewRecorder() 193 req, err := http.NewRequest("GET", "http://localhost/nocache", nil) 194 if err != nil { 195 t.Fatal(err) 196 } 197 req.Header.Set("ETag", "abcdef") 198 nc.ServeHTTP(rw, req) 199 h := rw.Header() 200 if expected := "no-cache, no-store, must-revalidate"; expected != h.Get("Cache-Control") { 201 t.Errorf("invalid cache-control header: expected: %s got: %s", expected, h.Get("Cache-Control")) 202 } 203 if expected := "no-cache"; expected != h.Get("Pragma") { 204 t.Errorf("invalid pragma header: expected: %s got: %s", expected, h.Get("Pragma")) 205 } 206 if expected := "0"; expected != h.Get("Expires") { 207 t.Errorf("invalid expires header: expected: %s got: %s", expected, h.Get("Expires")) 208 } 209 if expected := ""; expected != h.Get("ETag") { 210 t.Errorf("invalid etag header: expected: %s got: %s", expected, h.Get("ETag")) 211 } 212 } 213 214 var testDefReqConfig = config.DefReqConfig{ 215 Type: "file", 216 FileSystem: config.DefReqFiles{ 217 FileName: "test_aliases.json", 218 }, 219 AliasInfo: true, 220 } 221 222 func TestLoadDefaultAliases(t *testing.T) { 223 defAliases, aliasJSON := readDefaultRequest(testDefReqConfig) 224 expectedJSON := []byte(`{"ext":{"prebid":{"aliases": {"test1": "appnexus", "test2": "rubicon", "test3": "openx"}}}}`) 225 expectedAliases := map[string]string{ 226 "test1": "appnexus", 227 "test2": "rubicon", 228 "test3": "openx", 229 } 230 231 assert.JSONEq(t, string(expectedJSON), string(aliasJSON)) 232 assert.Equal(t, expectedAliases, defAliases) 233 } 234 235 func TestLoadDefaultAliasesNoInfo(t *testing.T) { 236 noInfoConfig := testDefReqConfig 237 noInfoConfig.AliasInfo = false 238 defAliases, aliasJSON := readDefaultRequest(noInfoConfig) 239 expectedJSON := []byte(`{"ext":{"prebid":{"aliases": {"test1": "appnexus", "test2": "rubicon", "test3": "openx"}}}}`) 240 expectedAliases := map[string]string{} 241 242 assert.JSONEq(t, string(expectedJSON), string(aliasJSON)) 243 assert.Equal(t, expectedAliases, defAliases) 244 } 245 246 func TestValidateDefaultAliases(t *testing.T) { 247 var testCases = []struct { 248 description string 249 givenAliases map[string]string 250 expectedError string 251 }{ 252 { 253 description: "None", 254 givenAliases: map[string]string{}, 255 expectedError: "", 256 }, 257 { 258 description: "Valid", 259 givenAliases: map[string]string{"aAlias": "a"}, 260 expectedError: "", 261 }, 262 { 263 description: "Invalid", 264 givenAliases: map[string]string{"all": "a"}, 265 expectedError: "default request alias errors (1 error):\n 1: alias all is a reserved bidder name and cannot be used\n", 266 }, 267 { 268 description: "Mixed", 269 givenAliases: map[string]string{"aAlias": "a", "all": "a"}, 270 expectedError: "default request alias errors (1 error):\n 1: alias all is a reserved bidder name and cannot be used\n", 271 }, 272 } 273 274 for _, test := range testCases { 275 err := validateDefaultAliases(test.givenAliases) 276 277 if test.expectedError == "" { 278 assert.NoError(t, err, test.description) 279 } else { 280 assert.EqualError(t, err, test.expectedError, test.description) 281 } 282 } 283 } 284 285 func TestBidderParamsCompactedOutput(t *testing.T) { 286 expectedFormattedResponse := `{"appnexus":{"$schema":"http://json-schema.org/draft-04/schema#","title":"Sample schema","description":"A sample schema to test the bidder/params endpoint","type":"object","properties":{"integer_param":{"type":"integer","minimum":1,"description":"A customer id"},"string_param_1":{"type":"string","minLength":1,"description":"Text with blanks in between"},"string_param_2":{"type":"string","minLength":1,"description":"Text_with_no_blanks_in_between"}},"required":["integer_param","string_param_2"]}}` 287 288 // Setup 289 inSchemaDirectory := "bidder_params_tests" 290 paramsValidator, err := openrtb_ext.NewBidderParamsValidator(inSchemaDirectory) 291 assert.NoError(t, err, "Error initialing validator") 292 293 handler := newJsonDirectoryServer(inSchemaDirectory, paramsValidator, nil, nil) 294 recorder := httptest.NewRecorder() 295 request, err := http.NewRequest("GET", "/bidder/params", nil) 296 assert.NoError(t, err, "Error creating request") 297 298 // Run 299 handler(recorder, request, nil) 300 301 // Assertions 302 assert.Equal(t, expectedFormattedResponse, recorder.Body.String()) 303 }