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  }