github.com/prebid/prebid-server@v0.275.0/endpoints/events/event_test.go (about)

     1  package events
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"errors"
     8  	"io"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/prebid/prebid-server/analytics"
    16  	"github.com/prebid/prebid-server/config"
    17  	"github.com/prebid/prebid-server/errortypes"
    18  	"github.com/prebid/prebid-server/metrics"
    19  	"github.com/prebid/prebid-server/stored_requests"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  // Mock Analytics Module
    24  type eventsMockAnalyticsModule struct {
    25  	Fail    bool
    26  	Error   error
    27  	Invoked bool
    28  }
    29  
    30  func (e *eventsMockAnalyticsModule) LogAuctionObject(ao *analytics.AuctionObject) {
    31  	if e.Fail {
    32  		panic(e.Error)
    33  	}
    34  	return
    35  }
    36  
    37  func (e *eventsMockAnalyticsModule) LogVideoObject(vo *analytics.VideoObject) {
    38  	if e.Fail {
    39  		panic(e.Error)
    40  	}
    41  	return
    42  }
    43  
    44  func (e *eventsMockAnalyticsModule) LogCookieSyncObject(cso *analytics.CookieSyncObject) {
    45  	if e.Fail {
    46  		panic(e.Error)
    47  	}
    48  	return
    49  }
    50  
    51  func (e *eventsMockAnalyticsModule) LogSetUIDObject(so *analytics.SetUIDObject) {
    52  	if e.Fail {
    53  		panic(e.Error)
    54  	}
    55  	return
    56  }
    57  
    58  func (e *eventsMockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject) {
    59  	if e.Fail {
    60  		panic(e.Error)
    61  	}
    62  	return
    63  }
    64  
    65  func (e *eventsMockAnalyticsModule) LogNotificationEventObject(ne *analytics.NotificationEvent) {
    66  	if e.Fail {
    67  		panic(e.Error)
    68  	}
    69  	e.Invoked = true
    70  
    71  	return
    72  }
    73  
    74  // Mock Account fetcher
    75  var mockAccountData = map[string]json.RawMessage{
    76  	"events_enabled":  json.RawMessage(`{"events": {"enabled":true}}`),
    77  	"events_disabled": json.RawMessage(`{"events": {"enabled":false}}`),
    78  	"malformed_acct":  json.RawMessage(`{"events": {"enabled":"invalid type"}}`),
    79  }
    80  
    81  type mockAccountsFetcher struct {
    82  	Fail       bool
    83  	Error      error
    84  	DurationMS int
    85  }
    86  
    87  func (maf mockAccountsFetcher) FetchAccount(ctx context.Context, defaultAccountJSON json.RawMessage, accountID string) (json.RawMessage, []error) {
    88  	if maf.DurationMS > 0 {
    89  		select {
    90  		case <-time.After(time.Duration(maf.DurationMS) * time.Millisecond):
    91  			break
    92  		case <-ctx.Done():
    93  			return nil, []error{ctx.Err()}
    94  		}
    95  	}
    96  
    97  	if account, ok := mockAccountData[accountID]; ok {
    98  		return account, nil
    99  	}
   100  
   101  	if maf.Fail {
   102  		return nil, []error{maf.Error}
   103  	}
   104  
   105  	return nil, []error{stored_requests.NotFoundError{accountID, "Account"}}
   106  }
   107  
   108  // Tests
   109  
   110  func TestShouldReturnBadRequestWhenTypeIsMissing(t *testing.T) {
   111  
   112  	// mock AccountsFetcher
   113  	mockAccountsFetcher := &mockAccountsFetcher{}
   114  
   115  	// mock PBS Analytics Module
   116  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   117  		Fail: false,
   118  	}
   119  
   120  	// mock config
   121  	cfg := &config.Configuration{
   122  		AccountDefaults: config.Account{},
   123  	}
   124  
   125  	// prepare
   126  	reqData := ""
   127  
   128  	req := httptest.NewRequest("GET", "/event?b=test", strings.NewReader(reqData))
   129  	recorder := httptest.NewRecorder()
   130  
   131  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   132  
   133  	// execute
   134  	e(recorder, req, nil)
   135  
   136  	d, err := io.ReadAll(recorder.Result().Body)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  
   141  	// validate
   142  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with missing type parameter")
   143  	assert.Equal(t, "invalid request: parameter 't' is required\n", string(d))
   144  }
   145  
   146  func TestShouldReturnBadRequestWhenTypeIsInvalid(t *testing.T) {
   147  
   148  	// mock AccountsFetcher
   149  	mockAccounts := &mockAccountsFetcher{}
   150  
   151  	// mock PBS Analytics Module
   152  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   153  		Fail: false,
   154  	}
   155  
   156  	// mock config
   157  	cfg := &config.Configuration{
   158  		AccountDefaults: config.Account{},
   159  	}
   160  
   161  	// prepare
   162  	reqData := ""
   163  
   164  	req := httptest.NewRequest("GET", "/event?t=test&b=t", strings.NewReader(reqData))
   165  	recorder := httptest.NewRecorder()
   166  
   167  	e := NewEventEndpoint(cfg, mockAccounts, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   168  
   169  	// execute
   170  	e(recorder, req, nil)
   171  
   172  	d, err := io.ReadAll(recorder.Result().Body)
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  
   177  	// validate
   178  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid type parameter")
   179  	assert.Equal(t, "invalid request: unknown type: 'test'\n", string(d))
   180  }
   181  
   182  func TestShouldReturnBadRequestWhenBidIdIsMissing(t *testing.T) {
   183  
   184  	// mock AccountsFetcher
   185  	mockAccountsFetcher := &mockAccountsFetcher{}
   186  
   187  	// mock PBS Analytics Module
   188  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   189  		Fail: false,
   190  	}
   191  
   192  	// mock config
   193  	cfg := &config.Configuration{
   194  		AccountDefaults: config.Account{},
   195  	}
   196  
   197  	// prepare
   198  	reqData := ""
   199  
   200  	req := httptest.NewRequest("GET", "/event?t=win", strings.NewReader(reqData))
   201  	recorder := httptest.NewRecorder()
   202  
   203  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   204  
   205  	// execute
   206  	e(recorder, req, nil)
   207  
   208  	d, err := io.ReadAll(recorder.Result().Body)
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  
   213  	// validate
   214  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with missing bidid parameter")
   215  	assert.Equal(t, "invalid request: parameter 'b' is required\n", string(d))
   216  }
   217  
   218  func TestShouldReturnBadRequestWhenTimestampIsInvalid(t *testing.T) {
   219  
   220  	// mock AccountsFetcher
   221  	mockAccountsFetcher := &mockAccountsFetcher{}
   222  
   223  	// mock PBS Analytics Module
   224  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   225  		Fail: false,
   226  	}
   227  
   228  	// mock config
   229  	cfg := &config.Configuration{
   230  		AccountDefaults: config.Account{},
   231  	}
   232  
   233  	// prepare
   234  	reqData := ""
   235  
   236  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=q", strings.NewReader(reqData))
   237  	recorder := httptest.NewRecorder()
   238  
   239  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   240  
   241  	// execute
   242  	e(recorder, req, nil)
   243  
   244  	d, err := io.ReadAll(recorder.Result().Body)
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	// validate
   250  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid timestamp parameter")
   251  	assert.Equal(t, "invalid request: invalid request: error parsing timestamp 'q'\n", string(d))
   252  }
   253  
   254  func TestShouldReturnUnauthorizedWhenAccountIsMissing(t *testing.T) {
   255  
   256  	// mock AccountsFetcher
   257  	mockAccountsFetcher := &mockAccountsFetcher{}
   258  
   259  	// mock PBS Analytics Module
   260  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   261  		Fail: false,
   262  	}
   263  
   264  	// mock config
   265  	cfg := &config.Configuration{
   266  		AccountDefaults: config.Account{},
   267  	}
   268  
   269  	// prepare
   270  	reqData := ""
   271  
   272  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234", strings.NewReader(reqData))
   273  	recorder := httptest.NewRecorder()
   274  
   275  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   276  
   277  	// execute
   278  	e(recorder, req, nil)
   279  
   280  	d, err := io.ReadAll(recorder.Result().Body)
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  
   285  	// validate
   286  	assert.Equal(t, 401, recorder.Result().StatusCode, "Expected 401 on request with missing account id parameter")
   287  	assert.Equal(t, "Account 'a' is required query parameter and can't be empty", string(d))
   288  }
   289  
   290  func TestShouldReturnBadRequestWhenFormatValueIsInvalid(t *testing.T) {
   291  
   292  	// mock AccountsFetcher
   293  	mockAccountsFetcher := &mockAccountsFetcher{}
   294  
   295  	// mock PBS Analytics Module
   296  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   297  		Fail: false,
   298  	}
   299  
   300  	// mock config
   301  	cfg := &config.Configuration{
   302  		AccountDefaults: config.Account{},
   303  	}
   304  
   305  	// prepare
   306  	reqData := ""
   307  
   308  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=q", strings.NewReader(reqData))
   309  	recorder := httptest.NewRecorder()
   310  
   311  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   312  
   313  	// execute
   314  	e(recorder, req, nil)
   315  
   316  	d, err := io.ReadAll(recorder.Result().Body)
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  
   321  	// validate
   322  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid format parameter")
   323  	assert.Equal(t, "invalid request: unknown format: 'q'\n", string(d))
   324  }
   325  
   326  func TestShouldReturnBadRequestWhenAnalyticsValueIsInvalid(t *testing.T) {
   327  
   328  	// mock AccountsFetcher
   329  	mockAccountsFetcher := &mockAccountsFetcher{}
   330  
   331  	// mock PBS Analytics Module
   332  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   333  		Fail: false,
   334  	}
   335  
   336  	// mock config
   337  	cfg := &config.Configuration{
   338  		AccountDefaults: config.Account{},
   339  	}
   340  
   341  	// prepare
   342  	reqData := ""
   343  
   344  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=4", strings.NewReader(reqData))
   345  	recorder := httptest.NewRecorder()
   346  
   347  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   348  
   349  	// execute
   350  	e(recorder, req, nil)
   351  
   352  	d, err := io.ReadAll(recorder.Result().Body)
   353  	if err != nil {
   354  		t.Fatal(err)
   355  	}
   356  
   357  	// validate
   358  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid analytics parameter")
   359  	assert.Equal(t, "invalid request: unknown analytics: '4'\n", string(d))
   360  }
   361  
   362  func TestShouldNotPassEventToAnalyticsReporterWhenAccountNotFoundAndDefaultIsFalse(t *testing.T) {
   363  
   364  	// mock AccountsFetcher
   365  	mockAccountsFetcher := &mockAccountsFetcher{
   366  		Fail:  true,
   367  		Error: stored_requests.NotFoundError{ID: "testacc"},
   368  	}
   369  
   370  	// mock PBS Analytics Module
   371  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   372  		Fail: false,
   373  	}
   374  
   375  	// mock config
   376  	cfg := &config.Configuration{
   377  		AccountDefaults: config.Account{},
   378  	}
   379  
   380  	// prepare
   381  	reqData := ""
   382  
   383  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=1&a=testacc", strings.NewReader(reqData))
   384  	recorder := httptest.NewRecorder()
   385  
   386  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   387  
   388  	// execute
   389  	e(recorder, req, nil)
   390  	d, err := io.ReadAll(recorder.Result().Body)
   391  	if err != nil {
   392  		t.Fatal(err)
   393  	}
   394  
   395  	// validate
   396  	assert.Equal(t, 401, recorder.Result().StatusCode, "Expected 401 on account not found")
   397  	assert.Equal(t, "Account 'testacc' doesn't support events", string(d))
   398  }
   399  
   400  func TestShouldReturnBadRequestWhenIntegrationValueIsInvalid(t *testing.T) {
   401  	// mock AccountsFetcher
   402  	mockAccountsFetcher := &mockAccountsFetcher{}
   403  
   404  	// mock PBS Analytics Module
   405  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   406  		Fail: false,
   407  	}
   408  
   409  	// mock config
   410  	cfg := &config.Configuration{
   411  		AccountDefaults: config.Account{},
   412  	}
   413  
   414  	// prepare
   415  	reqData := ""
   416  
   417  	req := httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=Te$tIntegrationType", strings.NewReader(reqData))
   418  	recorder := httptest.NewRecorder()
   419  
   420  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   421  
   422  	// execute
   423  	e(recorder, req, nil)
   424  
   425  	d, err := io.ReadAll(recorder.Result().Body)
   426  	if err != nil {
   427  		t.Fatal(err)
   428  	}
   429  
   430  	// validate
   431  	assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid integration type parameter")
   432  	assert.Equal(t, "invalid request: integration type can only contain numbers, letters and these characters '-', '_'\n", string(d))
   433  }
   434  
   435  func TestShouldNotPassEventToAnalyticsReporterWhenAccountEventNotEnabled(t *testing.T) {
   436  
   437  	// mock AccountsFetcher
   438  	mockAccountsFetcher := &mockAccountsFetcher{
   439  		Fail: false,
   440  	}
   441  
   442  	// mock PBS Analytics Module
   443  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   444  		Fail: false,
   445  	}
   446  
   447  	// mock config
   448  	cfg := &config.Configuration{
   449  		AccountDefaults: config.Account{},
   450  	}
   451  	cfg.MarshalAccountDefaults()
   452  
   453  	// prepare
   454  	reqData := ""
   455  
   456  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=1&a=events_disabled", strings.NewReader(reqData))
   457  	recorder := httptest.NewRecorder()
   458  
   459  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   460  
   461  	// execute
   462  	e(recorder, req, nil)
   463  	d, err := io.ReadAll(recorder.Result().Body)
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  
   468  	// validate
   469  	assert.Equal(t, 401, recorder.Result().StatusCode, "Expected 401 on account with events disabled")
   470  	assert.Equal(t, "Account 'events_disabled' doesn't support events", string(d))
   471  }
   472  
   473  func TestShouldPassEventToAnalyticsReporterWhenAccountEventEnabled(t *testing.T) {
   474  
   475  	// mock AccountsFetcher
   476  	mockAccountsFetcher := &mockAccountsFetcher{
   477  		Fail: false,
   478  	}
   479  
   480  	// mock PBS Analytics Module
   481  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   482  		Fail: false,
   483  	}
   484  
   485  	// mock config
   486  	cfg := &config.Configuration{
   487  		AccountDefaults: config.Account{},
   488  	}
   489  	cfg.MarshalAccountDefaults()
   490  
   491  	// prepare
   492  	reqData := ""
   493  
   494  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=1&a=events_enabled", strings.NewReader(reqData))
   495  	recorder := httptest.NewRecorder()
   496  
   497  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   498  
   499  	// execute
   500  	e(recorder, req, nil)
   501  
   502  	// validate
   503  	assert.Equal(t, 204, recorder.Result().StatusCode, "Expected 204 when account has events enabled")
   504  	assert.Equal(t, true, mockAnalyticsModule.Invoked)
   505  }
   506  
   507  func TestShouldNotPassEventToAnalyticsReporterWhenAnalyticsValueIsZero(t *testing.T) {
   508  
   509  	// mock AccountsFetcher
   510  	mockAccountsFetcher := &mockAccountsFetcher{
   511  		Fail: false,
   512  	}
   513  
   514  	// mock PBS Analytics Module
   515  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   516  		Fail: false,
   517  	}
   518  
   519  	// mock config
   520  	cfg := &config.Configuration{
   521  		AccountDefaults: config.Account{},
   522  	}
   523  	cfg.MarshalAccountDefaults()
   524  
   525  	// prepare
   526  	reqData := ""
   527  
   528  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=0&a=events_enabled", strings.NewReader(reqData))
   529  	recorder := httptest.NewRecorder()
   530  
   531  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   532  
   533  	// execute
   534  	e(recorder, req, nil)
   535  
   536  	// validate
   537  	assert.Equal(t, 204, recorder.Result().StatusCode)
   538  	assert.Equal(t, true, mockAnalyticsModule.Invoked != true)
   539  }
   540  
   541  func TestShouldRespondWithPixelAndContentTypeWhenRequestFormatIsImage(t *testing.T) {
   542  
   543  	// mock AccountsFetcher
   544  	mockAccountsFetcher := &mockAccountsFetcher{
   545  		Fail: false,
   546  	}
   547  
   548  	// mock PBS Analytics Module
   549  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   550  		Fail: false,
   551  	}
   552  
   553  	// mock config
   554  	cfg := &config.Configuration{
   555  		AccountDefaults: config.Account{},
   556  	}
   557  	cfg.MarshalAccountDefaults()
   558  
   559  	// prepare
   560  	reqData := ""
   561  
   562  	req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=i&x=1&a=events_enabled", strings.NewReader(reqData))
   563  	recorder := httptest.NewRecorder()
   564  
   565  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   566  
   567  	// execute
   568  	e(recorder, req, nil)
   569  
   570  	d, err := io.ReadAll(recorder.Result().Body)
   571  	if err != nil {
   572  		t.Fatal(err)
   573  	}
   574  
   575  	// validate
   576  	assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 with tracking pixel when format is imp")
   577  	assert.Equal(t, true, mockAnalyticsModule.Invoked)
   578  	assert.Equal(t, "image/png", recorder.Header().Get("Content-Type"))
   579  	assert.Equal(t, "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABHNCSVQICAgIfAhkiAAAAA1JREFUCJljYGBgYAAAAAUAAYehTtQAAAAASUVORK5CYII=", base64.URLEncoding.EncodeToString(d))
   580  }
   581  
   582  func TestShouldRespondWithNoContentWhenRequestFormatIsNotDefined(t *testing.T) {
   583  
   584  	// mock AccountsFetcher
   585  	mockAccountsFetcher := &mockAccountsFetcher{
   586  		Fail: false,
   587  	}
   588  
   589  	// mock PBS Analytics Module
   590  	mockAnalyticsModule := &eventsMockAnalyticsModule{
   591  		Fail: false,
   592  	}
   593  
   594  	// mock config
   595  	cfg := &config.Configuration{
   596  		AccountDefaults: config.Account{},
   597  	}
   598  	cfg.MarshalAccountDefaults()
   599  
   600  	// prepare
   601  	reqData := ""
   602  
   603  	req := httptest.NewRequest("GET", "/event?t=imp&b=test&ts=1234&x=1&a=events_enabled", strings.NewReader(reqData))
   604  	recorder := httptest.NewRecorder()
   605  
   606  	e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   607  
   608  	// execute
   609  	e(recorder, req, nil)
   610  
   611  	d, err := io.ReadAll(recorder.Result().Body)
   612  	if err != nil {
   613  		t.Fatal(err)
   614  	}
   615  
   616  	// validate
   617  	assert.Equal(t, 204, recorder.Result().StatusCode, "Expected 200 with empty response")
   618  	assert.Equal(t, true, mockAnalyticsModule.Invoked)
   619  	assert.Equal(t, "", recorder.Header().Get("Content-Type"))
   620  	assert.Equal(t, 0, len(d))
   621  }
   622  
   623  func TestShouldParseEventCorrectly(t *testing.T) {
   624  
   625  	tests := map[string]struct {
   626  		req      *http.Request
   627  		expected *analytics.EventRequest
   628  	}{
   629  		"one": {
   630  			req: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=intType", strings.NewReader("")),
   631  			expected: &analytics.EventRequest{
   632  				Type:        analytics.Win,
   633  				BidID:       "bidId",
   634  				Timestamp:   1000,
   635  				Bidder:      "bidder",
   636  				AccountID:   "",
   637  				Format:      analytics.Blank,
   638  				Analytics:   analytics.Enabled,
   639  				Integration: "intType",
   640  			},
   641  		},
   642  		"two": {
   643  			req: httptest.NewRequest("GET", "/event?t=win&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   644  			expected: &analytics.EventRequest{
   645  				Type:      analytics.Win,
   646  				BidID:     "bidId",
   647  				Timestamp: 0,
   648  				Analytics: analytics.Enabled,
   649  			},
   650  		},
   651  		"three - vtype = start": {
   652  			req: httptest.NewRequest("GET", "/event?t=vast&vtype=start&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   653  			expected: &analytics.EventRequest{
   654  				Type:      analytics.Vast,
   655  				VType:     analytics.Start,
   656  				BidID:     "bidId",
   657  				Timestamp: 0,
   658  				Analytics: analytics.Enabled,
   659  			},
   660  		},
   661  	}
   662  
   663  	for name, test := range tests {
   664  		t.Run(name, func(t *testing.T) {
   665  
   666  			// execute
   667  			er, errs := ParseEventRequest(test.req)
   668  
   669  			// validate
   670  			assert.Equal(t, 0, len(errs))
   671  			assert.EqualValues(t, test.expected, er)
   672  		})
   673  	}
   674  }
   675  
   676  func TestEventRequestToUrl(t *testing.T) {
   677  	externalUrl := "http://localhost:8000"
   678  	tests := map[string]struct {
   679  		er   *analytics.EventRequest
   680  		want string
   681  	}{
   682  		"one": {
   683  			er: &analytics.EventRequest{
   684  				Type:      analytics.Imp,
   685  				BidID:     "bidid",
   686  				AccountID: "accountId",
   687  				Bidder:    "bidder",
   688  				Timestamp: 1234567,
   689  				Format:    analytics.Blank,
   690  				Analytics: analytics.Enabled,
   691  			},
   692  			want: "http://localhost:8000/event?t=imp&b=bidid&a=accountId&bidder=bidder&f=b&ts=1234567&x=1",
   693  		},
   694  		"two": {
   695  			er: &analytics.EventRequest{
   696  				Type:      analytics.Win,
   697  				BidID:     "bidid",
   698  				AccountID: "accountId",
   699  				Bidder:    "bidder",
   700  				Timestamp: 1234567,
   701  				Format:    analytics.Image,
   702  				Analytics: analytics.Disabled,
   703  			},
   704  			want: "http://localhost:8000/event?t=win&b=bidid&a=accountId&bidder=bidder&f=i&ts=1234567&x=0",
   705  		},
   706  		"three": {
   707  			er: &analytics.EventRequest{
   708  				Type:        analytics.Win,
   709  				BidID:       "bidid",
   710  				AccountID:   "accountId",
   711  				Bidder:      "bidder",
   712  				Timestamp:   1234567,
   713  				Format:      analytics.Image,
   714  				Analytics:   analytics.Disabled,
   715  				Integration: "integration",
   716  			},
   717  			want: "http://localhost:8000/event?t=win&b=bidid&a=accountId&bidder=bidder&f=i&int=integration&ts=1234567&x=0",
   718  		},
   719  	}
   720  
   721  	for name, test := range tests {
   722  		t.Run(name, func(t *testing.T) {
   723  			expected := EventRequestToUrl(externalUrl, test.er)
   724  			// validate
   725  			assert.Equal(t, test.want, expected)
   726  		})
   727  	}
   728  }
   729  
   730  func TestReadIntegrationType(t *testing.T) {
   731  	testCases := []struct {
   732  		description             string
   733  		givenHttpRequest        *http.Request
   734  		expectedIntegrationType string
   735  		expectedError           error
   736  	}{
   737  		{
   738  			description:             "Integration type in http request is valid, expect same integration time and no errors",
   739  			givenHttpRequest:        httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=TestIntegrationType", strings.NewReader("")),
   740  			expectedIntegrationType: "TestIntegrationType",
   741  			expectedError:           nil,
   742  		},
   743  		{
   744  			description:      "Integration type in http request is too long, expect too long error",
   745  			givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=TestIntegrationTypeTooLongTestIntegrationTypeTooLongTestIntegrationType", strings.NewReader("")),
   746  			expectedError:    errors.New("integration type length is too long"),
   747  		},
   748  		{
   749  			description:      "Integration type in http request contains invalid character, expect invalid character error",
   750  			givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=Te$tIntegrationType", strings.NewReader("")),
   751  			expectedError:    errors.New("integration type can only contain numbers, letters and these characters '-', '_'"),
   752  		},
   753  	}
   754  
   755  	for _, test := range testCases {
   756  		testEventRequest := &analytics.EventRequest{}
   757  		err := readIntegrationType(testEventRequest, test.givenHttpRequest)
   758  		if test.expectedError != nil {
   759  			assert.Equal(t, test.expectedError, err, test.description)
   760  		} else {
   761  			assert.Empty(t, err, test.description)
   762  			assert.Equalf(t, test.expectedIntegrationType, testEventRequest.Integration, test.description)
   763  		}
   764  	}
   765  }
   766  
   767  func TestShouldReturnBadRequestWhenVTypeIsInvalid(t *testing.T) {
   768  
   769  	reqData := ""
   770  
   771  	tests := []struct {
   772  		description        string
   773  		req                *http.Request
   774  		expectedStatusCode int
   775  		expectedStatus     string
   776  	}{
   777  		{
   778  			description:        "vtype parameter is missing",
   779  			req:                httptest.NewRequest("GET", "/event?t=vast&b=bidID", strings.NewReader(reqData)),
   780  			expectedStatusCode: 400,
   781  			expectedStatus:     "invalid request: parameter 'vtype' is required\n",
   782  		},
   783  		{
   784  			description:        "invalid vtype parameter",
   785  			req:                httptest.NewRequest("GET", "/event?t=vast&vtype=abc&b=bidID", strings.NewReader(reqData)),
   786  			expectedStatusCode: 400,
   787  			expectedStatus:     "invalid request: unknown vtype: 'abc'\n",
   788  		},
   789  		{
   790  			description:        "vtype is passed when event != vast",
   791  			req:                httptest.NewRequest("GET", "/event?t=win&vtype=startc&b=bidID", strings.NewReader(reqData)),
   792  			expectedStatusCode: 400,
   793  			expectedStatus:     "invalid request: parameter 'vtype' is only required for t=vast\n",
   794  		},
   795  	}
   796  
   797  	for _, test := range tests {
   798  		mockAccountsFetcher := &mockAccountsFetcher{}
   799  
   800  		mockAnalyticsModule := &eventsMockAnalyticsModule{
   801  			Fail: false,
   802  		}
   803  
   804  		cfg := &config.Configuration{
   805  			AccountDefaults: config.Account{},
   806  		}
   807  
   808  		recorder := httptest.NewRecorder()
   809  
   810  		e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{})
   811  		e(recorder, test.req, nil)
   812  
   813  		d, err := io.ReadAll(recorder.Result().Body)
   814  		if err != nil {
   815  			t.Fatal(err)
   816  		}
   817  
   818  		assert.Equal(t, test.expectedStatusCode, recorder.Result().StatusCode, test.description)
   819  		assert.Equal(t, test.expectedStatus, string(d), test.description)
   820  
   821  	}
   822  }
   823  
   824  func TestReadVType(t *testing.T) {
   825  	type args struct {
   826  		er  *analytics.EventRequest
   827  		req *http.Request
   828  	}
   829  	tests := []struct {
   830  		name          string
   831  		args          args
   832  		expectedError error
   833  		expectedVType analytics.VastType
   834  	}{
   835  		{
   836  			name: "vtype = start",
   837  			args: args{
   838  				er: &analytics.EventRequest{
   839  					Type: analytics.Vast,
   840  				},
   841  				req: httptest.NewRequest("GET", "/event?t=vast&vtype=start&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   842  			},
   843  			expectedError: nil,
   844  			expectedVType: analytics.Start,
   845  		},
   846  		{
   847  			name: "vtype = firstQuartile",
   848  			args: args{
   849  				er: &analytics.EventRequest{
   850  					Type: analytics.Vast,
   851  				},
   852  				req: httptest.NewRequest("GET", "/event?t=vast&vtype=firstQuartile&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   853  			},
   854  			expectedError: nil,
   855  			expectedVType: analytics.FirstQuartile,
   856  		},
   857  		{
   858  			name: "vtype = midPoint",
   859  			args: args{
   860  				er: &analytics.EventRequest{
   861  					Type: analytics.Vast,
   862  				},
   863  				req: httptest.NewRequest("GET", "/event?t=vast&vtype=midPoint&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   864  			},
   865  			expectedError: nil,
   866  			expectedVType: analytics.MidPoint,
   867  		},
   868  		{
   869  			name: "vtype = thirdQuartile",
   870  			args: args{
   871  				er: &analytics.EventRequest{
   872  					Type: analytics.Vast,
   873  				},
   874  				req: httptest.NewRequest("GET", "/event?t=vast&vtype=thirdQuartile&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   875  			},
   876  			expectedError: nil,
   877  			expectedVType: analytics.ThirdQuartile,
   878  		},
   879  		{
   880  			name: "vtype = complete",
   881  			args: args{
   882  				er: &analytics.EventRequest{
   883  					Type: analytics.Vast,
   884  				},
   885  				req: httptest.NewRequest("GET", "/event?t=vast&vtype=complete&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   886  			},
   887  			expectedError: nil,
   888  			expectedVType: analytics.Complete,
   889  		},
   890  		{
   891  			name: "unknown vtype",
   892  			args: args{
   893  				er: &analytics.EventRequest{
   894  					Type: analytics.Vast,
   895  				},
   896  				req: httptest.NewRequest("GET", "/event?t=vast&vtype=test&b=bidId&ts=0&a=accountId", strings.NewReader("")),
   897  			},
   898  			expectedError: &errortypes.BadInput{Message: "unknown vtype: 'test'"},
   899  			expectedVType: "",
   900  		},
   901  	}
   902  	for _, tt := range tests {
   903  		t.Run(tt.name, func(t *testing.T) {
   904  			err := readVType(tt.args.er, tt.args.req)
   905  			assert.Equal(t, tt.expectedError, err, tt.name)
   906  			assert.Equal(t, tt.expectedVType, tt.args.er.VType, tt.name)
   907  		})
   908  	}
   909  }