Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single stored auction response #2132

Merged
merged 10 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions endpoints/openrtb2/amp_auction.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func NewAmpEndpoint(
disabledBidders map[string]string,
defReqJSON []byte,
bidderMap map[string]openrtb_ext.BidderName,
storedRespFetcher stored_requests.Fetcher,
) (httprouter.Handle, error) {

if ex == nil || validator == nil || requestsById == nil || accounts == nil || cfg == nil || met == nil {
Expand Down Expand Up @@ -88,7 +89,7 @@ func NewAmpEndpoint(
nil,
nil,
ipValidator,
empty_fetcher.EmptyFetcher{}}).AmpAuction), nil
storedRespFetcher}).AmpAuction), nil

}

Expand Down Expand Up @@ -136,7 +137,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
w.Header().Set("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin")
w.Header().Set("X-Prebid", version.BuildXPrebidHeader(version.Ver))

req, errL := deps.parseAmpRequest(r)
req, storedAuctionResponses, errL := deps.parseAmpRequest(r)
ao.Errors = append(ao.Errors, errL...)

if errortypes.ContainsFatalError(errL) {
Expand Down Expand Up @@ -199,6 +200,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
StartTime: start,
LegacyLabels: labels,
GlobalPrivacyControlHeader: secGPC,
StoredAuctionResponses: storedAuctionResponses,
}

response, err := deps.ex.HoldAuction(ctx, auctionRequest, nil)
Expand Down Expand Up @@ -299,9 +301,9 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
// possible, it will return errors with messages that suggest improvements.
//
// If the errors list has at least one element, then no guarantees are made about the returned request.
func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request) (req *openrtb2.BidRequest, errs []error) {
func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request) (req *openrtb2.BidRequest, storedAuctionResponses map[string]json.RawMessage, errs []error) {
// Load the stored request for the AMP ID.
req, e := deps.loadRequestJSONForAmp(httpRequest)
req, storedAuctionResponses, e := deps.loadRequestJSONForAmp(httpRequest)
if errs = append(errs, e...); errortypes.ContainsFatalError(errs) {
return
}
Expand All @@ -316,27 +318,28 @@ func (deps *endpointDeps) parseAmpRequest(httpRequest *http.Request) (req *openr
}

// At this point, we should have a valid request that definitely has Targeting and Cache turned on
e = deps.validateRequest(&openrtb_ext.RequestWrapper{BidRequest: req}, true)
hasStoredResponses := len(storedAuctionResponses) > 0
e = deps.validateRequest(&openrtb_ext.RequestWrapper{BidRequest: req}, true, hasStoredResponses)
errs = append(errs, e...)
return
}

// Load the stored OpenRTB request for an incoming AMP request, or return the errors found.
func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req *openrtb2.BidRequest, errs []error) {
func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req *openrtb2.BidRequest, storedAuctionResponses map[string]json.RawMessage, errs []error) {
req = &openrtb2.BidRequest{}
errs = nil

ampParams, err := amp.ParseParams(httpRequest)
if err != nil {
return nil, []error{err}
return nil, nil, []error{err}
}

ctx, cancel := context.WithTimeout(context.Background(), time.Duration(storedRequestTimeoutMillis)*time.Millisecond)
defer cancel()

storedRequests, _, errs := deps.storedReqFetcher.FetchRequests(ctx, []string{ampParams.StoredRequestID}, nil)
if len(errs) > 0 {
return nil, errs
return nil, nil, errs
}
if len(storedRequests) == 0 {
errs = []error{fmt.Errorf("No AMP config found for tag_id '%s'", ampParams.StoredRequestID)}
Expand All @@ -350,6 +353,12 @@ func (deps *endpointDeps) loadRequestJSONForAmp(httpRequest *http.Request) (req
return
}

storedAuctionResponses, errs = deps.processStoredAuctionResponses(ctx, requestJSON)
if err != nil {
errs = []error{err}
return
}

if deps.cfg.GenerateRequestID || req.ID == "{{UUID}}" {
newBidRequestId, err := deps.uuidGenerator.Generate()
if err != nil {
Expand Down
38 changes: 38 additions & 0 deletions endpoints/openrtb2/amp_auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ func TestGoodAmpRequests(t *testing.T) {
goodRequests := map[string]json.RawMessage{
"1": json.RawMessage(validRequest(t, "aliased-buyeruids.json")),
"2": json.RawMessage(validRequest(t, "aliases.json")),
"3": json.RawMessage(validRequest(t, "imp-with-stored-resp.json")),
"5": json.RawMessage(validRequest(t, "gdpr-no-consentstring.json")),
"6": json.RawMessage(validRequest(t, "gdpr.json")),
"7": json.RawMessage(validRequest(t, "site.json")),
"9": json.RawMessage(validRequest(t, "user.json")),
}

goodStoredResponses := map[string]json.RawMessage{
"6d718149": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"targeting": { "hb_pb": "1.20", "hb_cat": "IAB-20", "hb_cache_id": "some_id"}}}}],"seat": "appnexus"}]`),
}

endpoint, _ := NewAmpEndpoint(
fakeUUIDGenerator{},
&mockAmpExchange{},
Expand All @@ -50,6 +55,7 @@ func TestGoodAmpRequests(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
&mockAmpStoredResponseFetcher{goodStoredResponses},
)

for requestID := range goodRequests {
Expand Down Expand Up @@ -104,6 +110,7 @@ func TestAMPPageInfo(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)
request := httptest.NewRequest("GET", fmt.Sprintf("/openrtb2/auction/amp?tag_id=1&curl=%s", url.QueryEscape(page)), nil)
recorder := httptest.NewRecorder()
Expand Down Expand Up @@ -202,6 +209,7 @@ func TestGDPRConsent(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

// Invoke Endpoint
Expand Down Expand Up @@ -355,6 +363,7 @@ func TestCCPAConsent(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

// Invoke Endpoint
Expand Down Expand Up @@ -466,6 +475,7 @@ func TestConsentWarnings(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

// Invoke Endpoint
Expand Down Expand Up @@ -559,6 +569,7 @@ func TestNewAndLegacyConsentBothProvided(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

// Invoke Endpoint
Expand Down Expand Up @@ -611,6 +622,7 @@ func TestAMPSiteExt(t *testing.T) {
nil,
nil,
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)
request, err := http.NewRequest("GET", "/openrtb2/auction/amp?tag_id=1", nil)
if !assert.NoError(t, err) {
Expand Down Expand Up @@ -648,6 +660,7 @@ func TestAmpBadRequests(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)
for requestID := range badRequests {
request := httptest.NewRequest("GET", fmt.Sprintf("/openrtb2/auction/amp?tag_id=%s", requestID), nil)
Expand Down Expand Up @@ -679,6 +692,7 @@ func TestAmpDebug(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

for requestID := range requests {
Expand Down Expand Up @@ -752,6 +766,7 @@ func TestQueryParamOverrides(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

requestID := "1"
Expand Down Expand Up @@ -905,6 +920,7 @@ func (s formatOverrideSpec) execute(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

url := fmt.Sprintf("/openrtb2/auction/amp?tag_id=1&debug=1&w=%d&h=%d&ow=%d&oh=%d&ms=%s&account=%s", s.width, s.height, s.overrideWidth, s.overrideHeight, s.multisize, s.account)
Expand Down Expand Up @@ -947,6 +963,18 @@ func (cf *mockAmpStoredReqFetcher) FetchResponses(ctx context.Context, ids []str
return nil, nil
}

type mockAmpStoredResponseFetcher struct {
data map[string]json.RawMessage
}

func (cf *mockAmpStoredResponseFetcher) FetchRequests(ctx context.Context, requestIDs []string, impIDs []string) (requestData map[string]json.RawMessage, impData map[string]json.RawMessage, errs []error) {
return nil, nil, nil
}

func (cf *mockAmpStoredResponseFetcher) FetchResponses(ctx context.Context, ids []string) (data map[string]json.RawMessage, errs []error) {
return cf.data, nil
}

type mockAmpExchange struct {
lastRequest *openrtb2.BidRequest
}
Expand All @@ -972,6 +1000,14 @@ func (m *mockAmpExchange) HoldAuction(ctx context.Context, r exchange.AuctionReq
}},
Ext: json.RawMessage(`{ "errors": {"openx":[ { "code": 1, "message": "The request exceeded the timeout allocated" } ] } }`),
}
if len(r.StoredAuctionResponses) > 0 {
var seatBids []openrtb2.SeatBid

if err := json.Unmarshal(r.StoredAuctionResponses[r.BidRequest.Imp[0].ID], &seatBids); err != nil {
return nil, err
}
response.SeatBid = seatBids
}

if r.BidRequest.Test == 1 {
resolvedRequest, err := json.Marshal(r.BidRequest)
Expand Down Expand Up @@ -1360,6 +1396,7 @@ func ampObjectTestSetup(t *testing.T, inTagId string, inStoredRequest json.RawMe
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)
return &actualAmpObject, endpoint
}
Expand Down Expand Up @@ -1410,6 +1447,7 @@ func TestAmpAuctionResponseHeaders(t *testing.T) {
map[string]string{},
[]byte{},
openrtb_ext.BuildBidderMap(),
empty_fetcher.EmptyFetcher{},
)

for _, test := range testCases {
Expand Down
Loading