diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index d7442f5ecba..5536c4e6603 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -144,6 +144,8 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h return } + ao.Request = req + ctx := context.Background() var cancel context.CancelFunc if req.TMax > 0 { diff --git a/endpoints/openrtb2/amp_auction_test.go b/endpoints/openrtb2/amp_auction_test.go index 57e0a7b447d..f0cf1dcfe38 100644 --- a/endpoints/openrtb2/amp_auction_test.go +++ b/endpoints/openrtb2/amp_auction_test.go @@ -11,6 +11,7 @@ import ( "strconv" "testing" + "github.com/prebid/prebid-server/analytics" "github.com/prebid/prebid-server/stored_requests" "github.com/prebid/prebid-server/stored_requests/backends/empty_fetcher" @@ -1133,3 +1134,162 @@ func TestSetEffectiveAmpPubID(t *testing.T) { } } } + +type mockLogger struct { + ampObject *analytics.AmpObject +} + +func newMockLogger(ao *analytics.AmpObject) analytics.PBSAnalyticsModule { + return &mockLogger{ + ampObject: ao, + } +} + +func (logger mockLogger) LogAuctionObject(ao *analytics.AuctionObject) { + return +} +func (logger mockLogger) LogVideoObject(vo *analytics.VideoObject) { + return +} +func (logger mockLogger) LogCookieSyncObject(cookieObject *analytics.CookieSyncObject) { + return +} +func (logger mockLogger) LogSetUIDObject(uuidObj *analytics.SetUIDObject) { + return +} +func (logger mockLogger) LogAmpObject(ao *analytics.AmpObject) { + *logger.ampObject = *ao +} + +func TestBuildAmpObject(t *testing.T) { + testCases := []struct { + description string + inTagId string + inStoredRequest json.RawMessage + expectedAmpObject *analytics.AmpObject + }{ + { + description: "Stored Amp request with nil body. Only the error gets logged", + inTagId: "test", + inStoredRequest: nil, + expectedAmpObject: &analytics.AmpObject{ + Status: http.StatusOK, + Errors: []error{fmt.Errorf("unexpected end of JSON input")}, + }, + }, + { + description: "Stored Amp request with no imps that should return error. Only the error gets logged", + inTagId: "test", + inStoredRequest: json.RawMessage(`{"id":"some-request-id","site":{"page":"prebid.org"},"imp":[],"tmax":500}`), + expectedAmpObject: &analytics.AmpObject{ + Status: http.StatusOK, + Errors: []error{fmt.Errorf("data for tag_id='test' does not define the required imp array")}, + }, + }, + { + description: "Wrong tag_id, error gets logged", + inTagId: "unknown", + inStoredRequest: json.RawMessage(`{"id":"some-request-id","site":{"page":"prebid.org"},"imp":[{"id":"some-impression-id","banner":{"format":[{"w":300,"h":250}]},"ext":{"appnexus":{"placementId":12883451}}}],"tmax":500}`), + expectedAmpObject: &analytics.AmpObject{ + Status: http.StatusOK, + Errors: []error{fmt.Errorf("unexpected end of JSON input")}, + }, + }, + { + description: "Valid stored Amp request, correct tag_id, a valid response should be logged", + inTagId: "test", + inStoredRequest: json.RawMessage(`{"id":"some-request-id","site":{"page":"prebid.org"},"imp":[{"id":"some-impression-id","banner":{"format":[{"w":300,"h":250}]},"ext":{"appnexus":{"placementId":12883451}}}],"tmax":500}`), + expectedAmpObject: &analytics.AmpObject{ + Status: http.StatusOK, + Errors: nil, + Request: &openrtb.BidRequest{ + ID: "some-request-id", + Device: &openrtb.Device{ + IP: "192.0.2.1", + }, + Site: &openrtb.Site{ + Page: "prebid.org", + Publisher: &openrtb.Publisher{}, + Ext: json.RawMessage(`{"amp":1}`), + }, + Imp: []openrtb.Imp{ + { + ID: "some-impression-id", + Banner: &openrtb.Banner{ + Format: []openrtb.Format{ + { + W: 300, + H: 250, + }, + }, + }, + Secure: func(val int8) *int8 { return &val }(1), //(*int8)(1), + Ext: json.RawMessage(`{"appnexus":{"placementId":12883451}}`), + }, + }, + AT: 1, + TMax: 500, + Ext: json.RawMessage(`{"prebid":{"cache":{"bids":{"returnCreative":null},"vastxml":null},"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"includewinners":true,"includebidderkeys":true,"includebrandcategory":null,"includeformat":false,"durationrangesec":null}}}`), + }, + AuctionResponse: &openrtb.BidResponse{ + SeatBid: []openrtb.SeatBid{{ + Bid: []openrtb.Bid{{ + AdM: "", + Ext: json.RawMessage(`{ "prebid": {"targeting": { "hb_pb": "1.20", "hb_appnexus_pb": "1.20", "hb_cache_id": "some_id"}}}`), + }}, + Seat: "", + }}, + Ext: json.RawMessage(`{ "errors": {"openx":[ { "code": 1, "message": "The request exceeded the timeout allocated" } ] } }`), + }, + AmpTargetingValues: map[string]string{ + "hb_appnexus_pb": "1.20", + "hb_cache_id": "some_id", + "hb_pb": "1.20", + }, + Origin: "", + }, + }, + } + + request := httptest.NewRequest("GET", "/openrtb2/auction/amp?tag_id=test", nil) + recorder := httptest.NewRecorder() + + for _, test := range testCases { + + // Set up test, declare a new mock logger every time + actualAmpObject := new(analytics.AmpObject) + + logger := newMockLogger(actualAmpObject) + + mockAmpFetcher := &mockAmpStoredReqFetcher{ + data: map[string]json.RawMessage{ + test.inTagId: json.RawMessage(test.inStoredRequest), + }, + } + + endpoint, _ := NewAmpEndpoint( + &mockAmpExchange{}, + newParamsValidator(t), + mockAmpFetcher, + empty_fetcher.EmptyFetcher{}, + empty_fetcher.EmptyFetcher{}, + &config.Configuration{MaxRequestSize: maxSize}, + pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{}), + logger, + map[string]string{}, + []byte{}, + openrtb_ext.BidderMap, + ) + + // Run test + endpoint(recorder, request, nil) + + // assert AmpObject + assert.Equalf(t, test.expectedAmpObject.Status, actualAmpObject.Status, "Amp Object Status field doesn't match expected: %s\n", test.description) + assert.Lenf(t, actualAmpObject.Errors, len(test.expectedAmpObject.Errors), "Amp Object Errors array doesn't match expected: %s\n", test.description) + assert.Equalf(t, test.expectedAmpObject.Request, actualAmpObject.Request, "Amp Object BidRequest doesn't match expected: %s\n", test.description) + assert.Equalf(t, test.expectedAmpObject.AuctionResponse, actualAmpObject.AuctionResponse, "Amp Object BidResponse doesn't match expected: %s\n", test.description) + assert.Equalf(t, test.expectedAmpObject.AmpTargetingValues, actualAmpObject.AmpTargetingValues, "Amp Object AmpTargetingValues doesn't match expected: %s\n", test.description) + assert.Equalf(t, test.expectedAmpObject.Origin, actualAmpObject.Origin, "Amp Object Origin field doesn't match expected: %s\n", test.description) + } +}