From 4ea28659198f1bb2eb92c7a5fdc2ac2ba480a576 Mon Sep 17 00:00:00 2001 From: Kalidas Date: Mon, 23 Oct 2023 10:21:52 +0100 Subject: [PATCH 01/13] Added Alkimi adapter on PBS-GO --- adapters/alkimi/alkimi.go | 157 +++++++++++++++++++++++++++ adapters/alkimi/alkimi_test.go | 181 +++++++++++++++++++++++++++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_alkimi.go | 9 ++ static/bidder-info/alkimi.yaml | 15 +++ static/bidder-params/alkimi.json | 28 +++++ 7 files changed, 394 insertions(+) create mode 100644 adapters/alkimi/alkimi.go create mode 100644 adapters/alkimi/alkimi_test.go create mode 100644 openrtb_ext/imp_alkimi.go create mode 100644 static/bidder-info/alkimi.yaml create mode 100644 static/bidder-params/alkimi.json diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go new file mode 100644 index 00000000000..77aada32a06 --- /dev/null +++ b/adapters/alkimi/alkimi.go @@ -0,0 +1,157 @@ +package alkimi + +import ( + "encoding/json" + "fmt" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/floors" + "net/http" + "net/url" + "strings" + + "github.com/prebid/openrtb/v19/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" +) + +const PRICE_MACRO = "${AUCTION_PRICE}" + +type AlkimiAdapter struct { + endpoint string +} + +// Builder builds a new instance of the Alkimi adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + endpointURL, err := url.Parse(config.Endpoint) + if err != nil || len(endpointURL.String()) == 0 { + return nil, fmt.Errorf("invalid endpoint: %v", err) + } + + bidder := &AlkimiAdapter{ + endpoint: endpointURL.String(), + } + return bidder, nil +} + +// MakeRequests creates Alkimi adapter requests +func (adapter *AlkimiAdapter) MakeRequests(request *openrtb2.BidRequest, req *adapters.ExtraRequestInfo) (reqsBidder []*adapters.RequestData, errs []error) { + reqCopy := *request + reqCopy.Imp = _updateImps(reqCopy) + encoded, err := json.Marshal(reqCopy) + if err != nil { + errs = append(errs, err) + } else { + reqBidder := _buildBidderRequest(adapter, encoded) + reqsBidder = append(reqsBidder, reqBidder) + } + return +} + +func _updateImps(bidRequest openrtb2.BidRequest) []openrtb2.Imp { + updatedImps := make([]openrtb2.Imp, 0, len(bidRequest.Imp)) + for _, imp := range bidRequest.Imp { + var impExtAlkimi openrtb_ext.ImpExtAlkimi + if err := json.Unmarshal(imp.Ext, &impExtAlkimi); err == nil { + var bidFloorPrice floors.Price + bidFloorPrice.FloorMinCur = imp.BidFloorCur + bidFloorPrice.FloorMin = imp.BidFloor + + if len(bidFloorPrice.FloorMinCur) > 0 && bidFloorPrice.FloorMin > 0 { + imp.BidFloor = bidFloorPrice.FloorMin + } else { + imp.BidFloor = impExtAlkimi.BidFloor + } + imp.Instl = impExtAlkimi.Instl + imp.Exp = impExtAlkimi.Exp + + extJson, err := json.Marshal(impExtAlkimi) + if err != nil { + continue + } + imp.Ext = extJson + updatedImps = append(updatedImps, imp) + } + } + return updatedImps +} + +func _buildBidderRequest(adapter *AlkimiAdapter, encoded []byte) *adapters.RequestData { + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + reqBidder := &adapters.RequestData{ + Method: "POST", + Uri: adapter.endpoint, + Body: encoded, + Headers: headers, + } + return reqBidder +} + +// MakeBids will parse the bids from the Alkimi server +func (adapter *AlkimiAdapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + var errs []error + + if request == nil || response == nil || http.StatusNoContent == response.StatusCode { + return nil, nil + } + + var bidResp openrtb2.BidResponse + err := json.Unmarshal(response.Body, &bidResp) + if err != nil { + return nil, []error{err} + } + + bidCount := len(bidResp.SeatBid) + if bidCount > 0 { + bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidCount) + for _, seatBid := range bidResp.SeatBid { + for _, bid := range seatBid.Bid { + copyBid := bid + _resolveMacros(©Bid) + impId := copyBid.ImpID + imp := request.Imp + bidType, _ := _getMediaTypeForImp(impId, imp) + bidderBid := &adapters.TypedBid{ + Bid: ©Bid, + BidType: bidType, + Seat: "alkimi", + } + bidResponse.Bids = append(bidResponse.Bids, bidderBid) + } + } + return bidResponse, errs + } + return nil, nil +} + +func _resolveMacros(bid *openrtb2.Bid) { + price := bid.Price + strPrice := fmt.Sprint(price) + bid.NURL = strings.ReplaceAll(bid.NURL, PRICE_MACRO, strPrice) + bid.AdM = strings.ReplaceAll(bid.AdM, PRICE_MACRO, strPrice) +} + +func _getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { + for _, imp := range imps { + if imp.ID == impId { + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner, nil + } + if imp.Video != nil { + return openrtb_ext.BidTypeVideo, nil + } + if imp.Audio != nil { + return openrtb_ext.BidTypeAudio, nil + } + if imp.Native != nil { + return openrtb_ext.BidTypeNative, nil + } + } + } + return openrtb_ext.BidTypeBanner, &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to find imp \"%s\"", impId), + } +} diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go new file mode 100644 index 00000000000..80341526a16 --- /dev/null +++ b/adapters/alkimi/alkimi_test.go @@ -0,0 +1,181 @@ +package alkimi + +import ( + "encoding/json" + "github.com/prebid/openrtb/v19/openrtb2" + "github.com/prebid/prebid-server/adapters" + "testing" + + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +const ( + alkimiTestEndpoint = "https://exchange.alkimi-onboarding.com/server/bid" +) + +func TestEndpointEmpty(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ + Endpoint: ""}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + assert.Error(t, buildErr) +} + +func TestEndpointMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ + Endpoint: " http://leading.space.is.invalid"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + assert.Error(t, buildErr) +} + +func TestBuilder(t *testing.T) { + bidder, buildErr := buildBidder() + if buildErr != nil { + t.Fatalf("Failed to build bidder: %v", buildErr) + } + assert.NotNil(t, bidder) +} + +func TestMakeRequests(t *testing.T) { + // given + bidder, _ := buildBidder() + impExtAlkimi, _ := json.Marshal(openrtb_ext.ImpExtAlkimi{BidFloor: 5, Instl: 1, Exp: 2}) + bidRequest := openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + BidFloor: 6, + BidFloorCur: "", + Ext: impExtAlkimi, + }, + { + BidFloor: -1, + BidFloorCur: "USD", + Ext: impExtAlkimi, + }, + { + BidFloor: 10, + BidFloorCur: "USD", + Ext: impExtAlkimi, + }, + }, + } + // when + requestData, _ := bidder.MakeRequests(&bidRequest, nil) + request := requestData[0] + var updatedRequest openrtb2.BidRequest + errUnmarshal := json.Unmarshal(request.Body, &updatedRequest) + updatedImps := updatedRequest.Imp + // then + assert.Len(t, requestData, 1) + if errUnmarshal != nil { + t.Fatal("Corrupted updated request") + } + assert.Len(t, updatedImps, 3) + + assert.Equal(t, 5.0, updatedImps[0].BidFloor) + assert.Equal(t, int8(1), updatedImps[0].Instl) + assert.Equal(t, int64(2), updatedImps[0].Exp) + + assert.Equal(t, 5.0, updatedImps[1].BidFloor) + assert.Equal(t, int8(1), updatedImps[1].Instl) + assert.Equal(t, int64(2), updatedImps[1].Exp) + + assert.Equal(t, 10.0, updatedImps[2].BidFloor) + assert.Equal(t, int8(1), updatedImps[2].Instl) + assert.Equal(t, int64(2), updatedImps[2].Exp) +} + +func TestMakeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed(t *testing.T) { + // given + bidder, _ := buildBidder() + bid := openrtb2.Bid{ + ImpID: "impId-1", + AdM: "adm:${AUCTION_PRICE}", + NURL: "nurl:${AUCTION_PRICE}", + Price: 1, + } + sb := openrtb2.SeatBid{Bid: []openrtb2.Bid{bid}} + resp := openrtb2.BidResponse{SeatBid: []openrtb2.SeatBid{sb}} + respJson, jsonErr := json.Marshal(resp) + request := openrtb2.BidRequest{ + Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Banner: &openrtb2.Banner{}}), + } + // when + bids, errs := bidder.MakeBids(&request, nil, &adapters.ResponseData{ + StatusCode: 200, + Body: respJson, + }) + // then + if jsonErr != nil { + t.Fatalf("Failed to serialize test bid %v: %v", bid, jsonErr) + } + if len(errs) > 0 { + t.Fatalf("Failed to make bids: %v", errs) + } + assert.Len(t, bids.Bids, 1) + assert.Equal(t, "nurl:1", bids.Bids[0].Bid.NURL) + assert.Equal(t, "adm:1", bids.Bids[0].Bid.AdM) +} + +func TestMakeBidsShouldReturnEmptyListIfBidResponseIsNull(t *testing.T) { + // given + bidder, _ := buildBidder() + // when + bids, errs := bidder.MakeBids(&openrtb2.BidRequest{}, nil, nil) + // then + if len(errs) > 0 { + t.Fatalf("Failed to make bids: %v", errs) + } + assert.Nil(t, bids) +} + +func TestMakeBidsShouldReturnBidWithResolvedMacros(t *testing.T) { + // given + bidder, _ := buildBidder() + bid := openrtb2.Bid{ + ImpID: "impId-1", + AdM: "adm:${AUCTION_PRICE}", + NURL: "nurl:${AUCTION_PRICE}", + Price: 1, + } + seatBid := openrtb2.SeatBid{Bid: []openrtb2.Bid{bid}} + resp := openrtb2.BidResponse{SeatBid: []openrtb2.SeatBid{seatBid}} + respJson, jsonErr := json.Marshal(resp) + + request := openrtb2.BidRequest{ + Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Banner: &openrtb2.Banner{}}), + } + // when + bids, errs := bidder.MakeBids(&request, nil, &adapters.ResponseData{ + StatusCode: 200, + Body: respJson, + }) + // then + if jsonErr != nil { + t.Fatalf("Failed to serialize test bid %v: %v", bid, jsonErr) + } + if len(errs) > 0 { + t.Fatalf("Failed to make bids: %v", errs) + } + assert.Len(t, bids.Bids, 1) + assert.Equal(t, "nurl:1", bids.Bids[0].Bid.NURL) + assert.Equal(t, "adm:1", bids.Bids[0].Bid.AdM) +} + +func buildBidder() (adapters.Bidder, error) { + return Builder( + openrtb_ext.BidderAlkimi, + config.Adapter{Endpoint: alkimiTestEndpoint}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}, + ) +} + +//func TestJsonSamples(t *testing.T) { +// bidder, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ +// Endpoint: alkimiTestEndpoint}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) +// +// if buildErr != nil { +// t.Fatalf("Builder returned unexpected error %v", buildErr) +// } +// +// adapterstest.RunJSONBidderTest(t, "alkimitest", bidder) +//} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index d6b4400cd05..1c59e1e1fc3 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -32,6 +32,7 @@ import ( "github.com/prebid/prebid-server/adapters/aidem" "github.com/prebid/prebid-server/adapters/aja" "github.com/prebid/prebid-server/adapters/algorix" + "github.com/prebid/prebid-server/adapters/alkimi" "github.com/prebid/prebid-server/adapters/amx" "github.com/prebid/prebid-server/adapters/apacdex" "github.com/prebid/prebid-server/adapters/appnexus" @@ -224,6 +225,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAidem: aidem.Builder, openrtb_ext.BidderAJA: aja.Builder, openrtb_ext.BidderAlgorix: algorix.Builder, + openrtb_ext.BidderAlkimi: alkimi.Builder, openrtb_ext.BidderAMX: amx.Builder, openrtb_ext.BidderApacdex: apacdex.Builder, openrtb_ext.BidderAppnexus: appnexus.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index ae0f7b6c82a..2783d0bdfee 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -48,6 +48,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderAidem, BidderAJA, BidderAlgorix, + BidderAlkimi, BidderAMX, BidderApacdex, BidderAppnexus, @@ -328,6 +329,7 @@ const ( BidderAidem BidderName = "aidem" BidderAJA BidderName = "aja" BidderAlgorix BidderName = "algorix" + BidderAlkimi BidderName = "alkimi" BidderAMX BidderName = "amx" BidderApacdex BidderName = "apacdex" BidderAppnexus BidderName = "appnexus" diff --git a/openrtb_ext/imp_alkimi.go b/openrtb_ext/imp_alkimi.go new file mode 100644 index 00000000000..e413a70b2ba --- /dev/null +++ b/openrtb_ext/imp_alkimi.go @@ -0,0 +1,9 @@ +package openrtb_ext + +type ImpExtAlkimi struct { + Token string `json:"token"` + BidFloor float64 `json:"bidFloor"` + Instl int8 `json:"instl"` + Exp int64 `json:"exp"` + AdUnitCode string `json:"adUnitCode"` +} diff --git a/static/bidder-info/alkimi.yaml b/static/bidder-info/alkimi.yaml new file mode 100644 index 00000000000..e899521f8ad --- /dev/null +++ b/static/bidder-info/alkimi.yaml @@ -0,0 +1,15 @@ +adapters: + alkimi: + endpoint: https://exchange.alkimi-onboarding.com/server/bid + meta-info: + maintainer-email: support@alkimi.org + app-media-types: + - banner + - video + - audio + site-media-types: + - banner + - video + - audio + supported-vendors: + vendor-id: 0 diff --git a/static/bidder-params/alkimi.json b/static/bidder-params/alkimi.json new file mode 100644 index 00000000000..93e09022469 --- /dev/null +++ b/static/bidder-params/alkimi.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Alkimi Adapter Params", + "description": "A schema which validates params accepted by the Alkimi adapter", + "type": "object", + + "properties": { + "token": { + "type": "string", + "description": "Publisher Token provided by Alkimi" + }, + "bidFloor": { + "type": "number", + "description": "The minimum CPM price in USD", + "minimum": 0 + }, + "instl": { + "type": "number", + "description": "Set to 1 if using interstitial (default: 0)" + }, + "exp": { + "type": "number", + "description": "Advisory as to the number of seconds that may elapse between the auction and the actual impression" + } + }, + + "required": ["token"] +} From cf71f24d765a99d04d420bdd09aabe78e9ee3357 Mon Sep 17 00:00:00 2001 From: Kalidas Date: Mon, 30 Oct 2023 14:00:30 +0000 Subject: [PATCH 02/13] Imp structure updated --- adapters/alkimi/alkimi.go | 26 ++++++++++++++++++++------ adapters/alkimi/alkimi_test.go | 8 ++++---- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index 77aada32a06..13d074f55b1 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -21,6 +21,10 @@ type AlkimiAdapter struct { endpoint string } +type extObj struct { + AlkimiBidderExt openrtb_ext.ExtImpAlkimi `json:"bidder"` +} + // Builder builds a new instance of the Alkimi adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { endpointURL, err := url.Parse(config.Endpoint) @@ -51,8 +55,15 @@ func (adapter *AlkimiAdapter) MakeRequests(request *openrtb2.BidRequest, req *ad func _updateImps(bidRequest openrtb2.BidRequest) []openrtb2.Imp { updatedImps := make([]openrtb2.Imp, 0, len(bidRequest.Imp)) for _, imp := range bidRequest.Imp { - var impExtAlkimi openrtb_ext.ImpExtAlkimi - if err := json.Unmarshal(imp.Ext, &impExtAlkimi); err == nil { + + var bidderExt adapters.ExtImpBidder + var extImpAlkimi openrtb_ext.ExtImpAlkimi + + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil + } + + if err := json.Unmarshal(bidderExt.Bidder, &extImpAlkimi); err == nil { var bidFloorPrice floors.Price bidFloorPrice.FloorMinCur = imp.BidFloorCur bidFloorPrice.FloorMin = imp.BidFloor @@ -60,12 +71,15 @@ func _updateImps(bidRequest openrtb2.BidRequest) []openrtb2.Imp { if len(bidFloorPrice.FloorMinCur) > 0 && bidFloorPrice.FloorMin > 0 { imp.BidFloor = bidFloorPrice.FloorMin } else { - imp.BidFloor = impExtAlkimi.BidFloor + imp.BidFloor = extImpAlkimi.BidFloor } - imp.Instl = impExtAlkimi.Instl - imp.Exp = impExtAlkimi.Exp + imp.Instl = extImpAlkimi.Instl + imp.Exp = extImpAlkimi.Exp + + temp := extObj{AlkimiBidderExt: extImpAlkimi} + temp.AlkimiBidderExt.AdUnitCode = imp.ID - extJson, err := json.Marshal(impExtAlkimi) + extJson, err := json.Marshal(temp) if err != nil { continue } diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 80341526a16..707681667ca 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -38,23 +38,23 @@ func TestBuilder(t *testing.T) { func TestMakeRequests(t *testing.T) { // given bidder, _ := buildBidder() - impExtAlkimi, _ := json.Marshal(openrtb_ext.ImpExtAlkimi{BidFloor: 5, Instl: 1, Exp: 2}) + extImpAlkimi, _ := json.Marshal(extObj{AlkimiBidderExt: openrtb_ext.ExtImpAlkimi{BidFloor: 5, Instl: 1, Exp: 2}}) bidRequest := openrtb2.BidRequest{ Imp: []openrtb2.Imp{ { BidFloor: 6, BidFloorCur: "", - Ext: impExtAlkimi, + Ext: extImpAlkimi, }, { BidFloor: -1, BidFloorCur: "USD", - Ext: impExtAlkimi, + Ext: extImpAlkimi, }, { BidFloor: 10, BidFloorCur: "USD", - Ext: impExtAlkimi, + Ext: extImpAlkimi, }, }, } From b0a394cfc88f085450355eb9bd52fda89413bd52 Mon Sep 17 00:00:00 2001 From: Kalidas Date: Mon, 30 Oct 2023 14:25:14 +0000 Subject: [PATCH 03/13] Renamed the Imp structure --- openrtb_ext/imp_alkimi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openrtb_ext/imp_alkimi.go b/openrtb_ext/imp_alkimi.go index e413a70b2ba..640528f212f 100644 --- a/openrtb_ext/imp_alkimi.go +++ b/openrtb_ext/imp_alkimi.go @@ -1,6 +1,6 @@ package openrtb_ext -type ImpExtAlkimi struct { +type ExtImpAlkimi struct { Token string `json:"token"` BidFloor float64 `json:"bidFloor"` Instl int8 `json:"instl"` From 5811110b1f0779f08ba3e6f92e81f96e532a3eb8 Mon Sep 17 00:00:00 2001 From: Kalidas Date: Mon, 30 Oct 2023 17:27:45 +0000 Subject: [PATCH 04/13] Update alkimi adapter on adapters_builders.go file --- exchange/adapter_builders.go | 1 + 1 file changed, 1 insertion(+) diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 904a2ba7881..b8abd6dbbcb 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -32,6 +32,7 @@ import ( "github.com/prebid/prebid-server/v2/adapters/aidem" "github.com/prebid/prebid-server/v2/adapters/aja" "github.com/prebid/prebid-server/v2/adapters/algorix" + "github.com/prebid/prebid-server/v2/adapters/alkimi" "github.com/prebid/prebid-server/v2/adapters/amx" "github.com/prebid/prebid-server/v2/adapters/apacdex" "github.com/prebid/prebid-server/v2/adapters/appnexus" From 73f72d2d21aa73cd454148733eb6df77f2bf968e Mon Sep 17 00:00:00 2001 From: Kalidas Date: Mon, 30 Oct 2023 18:10:19 +0000 Subject: [PATCH 05/13] Updated imports according to prebid-server v2 --- adapters/alkimi/alkimi.go | 10 +++++----- adapters/alkimi/alkimi_test.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index 13d074f55b1..154038b7609 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -3,16 +3,16 @@ package alkimi import ( "encoding/json" "fmt" - "github.com/prebid/prebid-server/errortypes" - "github.com/prebid/prebid-server/floors" + "github.com/prebid/prebid-server/v2/errortypes" + "github.com/prebid/prebid-server/v2/floors" "net/http" "net/url" "strings" "github.com/prebid/openrtb/v19/openrtb2" - "github.com/prebid/prebid-server/adapters" - "github.com/prebid/prebid-server/config" - "github.com/prebid/prebid-server/openrtb_ext" + "github.com/prebid/prebid-server/v2/adapters" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" ) const PRICE_MACRO = "${AUCTION_PRICE}" diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 707681667ca..1f63fc7000e 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -3,11 +3,11 @@ package alkimi import ( "encoding/json" "github.com/prebid/openrtb/v19/openrtb2" - "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/v2/adapters" "testing" - "github.com/prebid/prebid-server/config" - "github.com/prebid/prebid-server/openrtb_ext" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) From 254642eda0f0d75f965e3ee2982ad4259858945b Mon Sep 17 00:00:00 2001 From: Kalidas Date: Tue, 31 Oct 2023 17:42:08 +0000 Subject: [PATCH 06/13] Update alkimi adapter according to review --- adapters/alkimi/alkimi.go | 104 ++++++++++++++++++++------------- adapters/alkimi/alkimi_test.go | 15 +---- adapters/alkimi/params_test.go | 48 +++++++++++++++ static/bidder-info/alkimi.yaml | 30 +++++----- 4 files changed, 129 insertions(+), 68 deletions(-) create mode 100644 adapters/alkimi/params_test.go diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index 154038b7609..47fc3cc3f37 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -7,6 +7,7 @@ import ( "github.com/prebid/prebid-server/v2/floors" "net/http" "net/url" + "strconv" "strings" "github.com/prebid/openrtb/v19/openrtb2" @@ -15,9 +16,9 @@ import ( "github.com/prebid/prebid-server/v2/openrtb_ext" ) -const PRICE_MACRO = "${AUCTION_PRICE}" +const price_macro = "${AUCTION_PRICE}" -type AlkimiAdapter struct { +type adapter struct { endpoint string } @@ -32,27 +33,35 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co return nil, fmt.Errorf("invalid endpoint: %v", err) } - bidder := &AlkimiAdapter{ + bidder := &adapter{ endpoint: endpointURL.String(), } return bidder, nil } // MakeRequests creates Alkimi adapter requests -func (adapter *AlkimiAdapter) MakeRequests(request *openrtb2.BidRequest, req *adapters.ExtraRequestInfo) (reqsBidder []*adapters.RequestData, errs []error) { +func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, req *adapters.ExtraRequestInfo) (reqsBidder []*adapters.RequestData, errs []error) { reqCopy := *request - reqCopy.Imp = _updateImps(reqCopy) + + updated, errs := updateImps(reqCopy) + if len(errs) > 0 || len(reqCopy.Imp) != len(updated) { + return nil, errs + } + + reqCopy.Imp = updated encoded, err := json.Marshal(reqCopy) if err != nil { errs = append(errs, err) } else { - reqBidder := _buildBidderRequest(adapter, encoded) + reqBidder := buildBidderRequest(adapter, encoded) reqsBidder = append(reqsBidder, reqBidder) } return } -func _updateImps(bidRequest openrtb2.BidRequest) []openrtb2.Imp { +func updateImps(bidRequest openrtb2.BidRequest) ([]openrtb2.Imp, []error) { + var errs []error + updatedImps := make([]openrtb2.Imp, 0, len(bidRequest.Imp)) for _, imp := range bidRequest.Imp { @@ -60,37 +69,43 @@ func _updateImps(bidRequest openrtb2.BidRequest) []openrtb2.Imp { var extImpAlkimi openrtb_ext.ExtImpAlkimi if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { - return nil + errs = append(errs, err) + continue + } + + if err := json.Unmarshal(bidderExt.Bidder, &extImpAlkimi); err != nil { + errs = append(errs, err) + continue } - if err := json.Unmarshal(bidderExt.Bidder, &extImpAlkimi); err == nil { - var bidFloorPrice floors.Price - bidFloorPrice.FloorMinCur = imp.BidFloorCur - bidFloorPrice.FloorMin = imp.BidFloor - - if len(bidFloorPrice.FloorMinCur) > 0 && bidFloorPrice.FloorMin > 0 { - imp.BidFloor = bidFloorPrice.FloorMin - } else { - imp.BidFloor = extImpAlkimi.BidFloor - } - imp.Instl = extImpAlkimi.Instl - imp.Exp = extImpAlkimi.Exp + var bidFloorPrice floors.Price + bidFloorPrice.FloorMinCur = imp.BidFloorCur + bidFloorPrice.FloorMin = imp.BidFloor + + if len(bidFloorPrice.FloorMinCur) > 0 && bidFloorPrice.FloorMin > 0 { + imp.BidFloor = bidFloorPrice.FloorMin + } else { + imp.BidFloor = extImpAlkimi.BidFloor + } + imp.Instl = extImpAlkimi.Instl + imp.Exp = extImpAlkimi.Exp - temp := extObj{AlkimiBidderExt: extImpAlkimi} - temp.AlkimiBidderExt.AdUnitCode = imp.ID + temp := extObj{AlkimiBidderExt: extImpAlkimi} + temp.AlkimiBidderExt.AdUnitCode = imp.ID - extJson, err := json.Marshal(temp) - if err != nil { - continue - } - imp.Ext = extJson - updatedImps = append(updatedImps, imp) + extJson, err := json.Marshal(temp) + if err != nil { + errs = append(errs, err) + continue } + imp.Ext = extJson + updatedImps = append(updatedImps, imp) } - return updatedImps + + return updatedImps, errs } -func _buildBidderRequest(adapter *AlkimiAdapter, encoded []byte) *adapters.RequestData { +func buildBidderRequest(adapter *adapter, encoded []byte) *adapters.RequestData { headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") headers.Add("Accept", "application/json") @@ -105,13 +120,17 @@ func _buildBidderRequest(adapter *AlkimiAdapter, encoded []byte) *adapters.Reque } // MakeBids will parse the bids from the Alkimi server -func (adapter *AlkimiAdapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { +func (adapter *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { var errs []error - if request == nil || response == nil || http.StatusNoContent == response.StatusCode { + if request == nil || response == nil || adapters.IsResponseStatusCodeNoContent(response) { return nil, nil } + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + var bidResp openrtb2.BidResponse err := json.Unmarshal(response.Body, &bidResp) if err != nil { @@ -124,10 +143,13 @@ func (adapter *AlkimiAdapter) MakeBids(request *openrtb2.BidRequest, externalReq for _, seatBid := range bidResp.SeatBid { for _, bid := range seatBid.Bid { copyBid := bid - _resolveMacros(©Bid) + resolveMacros(©Bid) impId := copyBid.ImpID imp := request.Imp - bidType, _ := _getMediaTypeForImp(impId, imp) + bidType, err := getMediaTypeForImp(impId, imp) + if err != nil { + errs = append(errs, err) + } bidderBid := &adapters.TypedBid{ Bid: ©Bid, BidType: bidType, @@ -141,14 +163,16 @@ func (adapter *AlkimiAdapter) MakeBids(request *openrtb2.BidRequest, externalReq return nil, nil } -func _resolveMacros(bid *openrtb2.Bid) { - price := bid.Price - strPrice := fmt.Sprint(price) - bid.NURL = strings.ReplaceAll(bid.NURL, PRICE_MACRO, strPrice) - bid.AdM = strings.ReplaceAll(bid.AdM, PRICE_MACRO, strPrice) +func resolveMacros(bid *openrtb2.Bid) { + if bid == nil { + return + } + strPrice := strconv.FormatFloat(bid.Price, 'f', -1, 64) + bid.NURL = strings.Replace(bid.NURL, price_macro, strPrice, -1) + bid.AdM = strings.Replace(bid.AdM, price_macro, strPrice, -1) } -func _getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { +func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { for _, imp := range imps { if imp.ID == impId { if imp.Banner != nil { diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 1f63fc7000e..7b2ded463dc 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -17,13 +17,13 @@ const ( func TestEndpointEmpty(t *testing.T) { _, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ - Endpoint: ""}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: ""}, config.Server{ExternalUrl: alkimiTestEndpoint, GvlID: 1, DataCenter: "2"}) assert.Error(t, buildErr) } func TestEndpointMalformed(t *testing.T) { _, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ - Endpoint: " http://leading.space.is.invalid"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + Endpoint: " http://leading.space.is.invalid"}, config.Server{ExternalUrl: alkimiTestEndpoint, GvlID: 1, DataCenter: "2"}) assert.Error(t, buildErr) } @@ -168,14 +168,3 @@ func buildBidder() (adapters.Bidder, error) { config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}, ) } - -//func TestJsonSamples(t *testing.T) { -// bidder, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ -// Endpoint: alkimiTestEndpoint}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) -// -// if buildErr != nil { -// t.Fatalf("Builder returned unexpected error %v", buildErr) -// } -// -// adapterstest.RunJSONBidderTest(t, "alkimitest", bidder) -//} diff --git a/adapters/alkimi/params_test.go b/adapters/alkimi/params_test.go new file mode 100644 index 00000000000..69142af8f33 --- /dev/null +++ b/adapters/alkimi/params_test.go @@ -0,0 +1,48 @@ +package alkimi + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderAlkimi, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderAlkimi, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"token": "ABC"}`, + `{"token": "ABC", "bidFloor": 1.0}`, + `{"token": "ABC", "instl": 1}`, + `{"token": "ABC", "exp": 30}`, +} + +var invalidParams = []string{ + `{"token": 42}`, + `{"token": "ABC", "bidFloor": "invalid"}`, + `{"token": "ABC", "instl": "invalid"}`, + `{"token": "ABC", "exp": "invalid"}`, +} diff --git a/static/bidder-info/alkimi.yaml b/static/bidder-info/alkimi.yaml index e899521f8ad..c27e2ca47e1 100644 --- a/static/bidder-info/alkimi.yaml +++ b/static/bidder-info/alkimi.yaml @@ -1,15 +1,15 @@ -adapters: - alkimi: - endpoint: https://exchange.alkimi-onboarding.com/server/bid - meta-info: - maintainer-email: support@alkimi.org - app-media-types: - - banner - - video - - audio - site-media-types: - - banner - - video - - audio - supported-vendors: - vendor-id: 0 +endpoint: https://exchange.alkimi-onboarding.com/server/bid +maintainer: + email: support@alkimi.org +gvlVendorID: 1169 +capabilities: + app: + mediaTypes: + - banner + - video + - audio + site: + mediaTypes: + - banner + - video + - audio From 773bf9284b13009f76872de97454ce7f1c486046 Mon Sep 17 00:00:00 2001 From: Kalidas Date: Thu, 2 Nov 2023 10:06:45 +0000 Subject: [PATCH 07/13] Removed tab spaces --- adapters/alkimi/alkimi.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index 47fc3cc3f37..0f20b57c96d 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -64,7 +64,7 @@ func updateImps(bidRequest openrtb2.BidRequest) ([]openrtb2.Imp, []error) { updatedImps := make([]openrtb2.Imp, 0, len(bidRequest.Imp)) for _, imp := range bidRequest.Imp { - + var bidderExt adapters.ExtImpBidder var extImpAlkimi openrtb_ext.ExtImpAlkimi @@ -77,7 +77,7 @@ func updateImps(bidRequest openrtb2.BidRequest) ([]openrtb2.Imp, []error) { errs = append(errs, err) continue } - + var bidFloorPrice floors.Price bidFloorPrice.FloorMinCur = imp.BidFloorCur bidFloorPrice.FloorMin = imp.BidFloor From 87a2333b826304b4bf6f605aae392ad14e60144e Mon Sep 17 00:00:00 2001 From: Kalidas Date: Thu, 9 Nov 2023 09:35:06 +0000 Subject: [PATCH 08/13] Updated the review comments --- adapters/alkimi/alkimi.go | 47 ++++++++------- adapters/alkimi/alkimi_test.go | 103 ++++++++++++++++++++++++++++++++- 2 files changed, 125 insertions(+), 25 deletions(-) diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index 0f20b57c96d..d298977791f 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -123,7 +123,7 @@ func buildBidderRequest(adapter *adapter, encoded []byte) *adapters.RequestData func (adapter *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { var errs []error - if request == nil || response == nil || adapters.IsResponseStatusCodeNoContent(response) { + if adapters.IsResponseStatusCodeNoContent(response) { return nil, nil } @@ -138,35 +138,34 @@ func (adapter *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest * } bidCount := len(bidResp.SeatBid) - if bidCount > 0 { - bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidCount) - for _, seatBid := range bidResp.SeatBid { - for _, bid := range seatBid.Bid { - copyBid := bid - resolveMacros(©Bid) - impId := copyBid.ImpID - imp := request.Imp - bidType, err := getMediaTypeForImp(impId, imp) - if err != nil { - errs = append(errs, err) - } - bidderBid := &adapters.TypedBid{ - Bid: ©Bid, - BidType: bidType, - Seat: "alkimi", - } - bidResponse.Bids = append(bidResponse.Bids, bidderBid) + if bidCount == 0 { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Empty SeatBid array", + }} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidCount) + for _, seatBid := range bidResp.SeatBid { + for _, bid := range seatBid.Bid { + copyBid := bid + resolveMacros(©Bid) + impId := copyBid.ImpID + imp := request.Imp + bidType, err := getMediaTypeForImp(impId, imp) + if err != nil { + errs = append(errs, err) } + bidderBid := &adapters.TypedBid{ + Bid: ©Bid, + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, bidderBid) } - return bidResponse, errs } - return nil, nil + return bidResponse, errs } func resolveMacros(bid *openrtb2.Bid) { - if bid == nil { - return - } strPrice := strconv.FormatFloat(bid.Price, 'f', -1, 64) bid.NURL = strings.Replace(bid.NURL, price_macro, strPrice, -1) bid.AdM = strings.Replace(bid.AdM, price_macro, strPrice, -1) diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 7b2ded463dc..5177b316251 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -116,11 +116,41 @@ func TestMakeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed(t *testing.T) { assert.Equal(t, "adm:1", bids.Bids[0].Bid.AdM) } +func TestMakeBidsShouldReturnErrorIfResponseBodyContainsIncorrectImp(t *testing.T) { + // given + bidder, _ := buildBidder() + bid := openrtb2.Bid{ + ImpID: "impId-1-incorrect", + AdM: "adm:${AUCTION_PRICE}", + NURL: "nurl:${AUCTION_PRICE}", + Price: 1, + } + sb := openrtb2.SeatBid{Bid: []openrtb2.Bid{bid}} + resp := openrtb2.BidResponse{SeatBid: []openrtb2.SeatBid{sb}} + respJson, jsonErr := json.Marshal(resp) + request := openrtb2.BidRequest{ + Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Banner: &openrtb2.Banner{}}), + } + // when + bids, errs := bidder.MakeBids(&request, nil, &adapters.ResponseData{ + StatusCode: 200, + Body: respJson, + }) + // then + if jsonErr != nil { + t.Fatalf("Failed to serialize test bid %v: %v", bid, jsonErr) + } + assert.Len(t, bids.Bids, 1) + assert.Len(t, errs, 1) +} + func TestMakeBidsShouldReturnEmptyListIfBidResponseIsNull(t *testing.T) { // given bidder, _ := buildBidder() // when - bids, errs := bidder.MakeBids(&openrtb2.BidRequest{}, nil, nil) + bids, errs := bidder.MakeBids(&openrtb2.BidRequest{}, nil, &adapters.ResponseData{ + StatusCode: 204, + }) // then if len(errs) > 0 { t.Fatalf("Failed to make bids: %v", errs) @@ -128,6 +158,18 @@ func TestMakeBidsShouldReturnEmptyListIfBidResponseIsNull(t *testing.T) { assert.Nil(t, bids) } +func TestMakeBidsShouldReturnEmptyListIfBidResponseIsError(t *testing.T) { + // given + bidder, _ := buildBidder() + // when + bids, errs := bidder.MakeBids(&openrtb2.BidRequest{}, nil, &adapters.ResponseData{ + StatusCode: 500, + }) + // then + assert.Len(t, errs, 1) + assert.Nil(t, bids) +} + func TestMakeBidsShouldReturnBidWithResolvedMacros(t *testing.T) { // given bidder, _ := buildBidder() @@ -161,6 +203,65 @@ func TestMakeBidsShouldReturnBidWithResolvedMacros(t *testing.T) { assert.Equal(t, "adm:1", bids.Bids[0].Bid.AdM) } +func TestMakeBidsShouldReturnBidForAllTypes(t *testing.T) { + // given + bidder, _ := buildBidder() + bid := openrtb2.Bid{ + ImpID: "impId-1", + AdM: "adm:${AUCTION_PRICE}", + NURL: "nurl:${AUCTION_PRICE}", + Price: 1, + } + seatBid := openrtb2.SeatBid{Bid: []openrtb2.Bid{bid}} + resp := openrtb2.BidResponse{SeatBid: []openrtb2.SeatBid{seatBid}} + respJson, jsonErr := json.Marshal(resp) + + request := openrtb2.BidRequest{ + Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Video: &openrtb2.Video{}}), + } + // when + bids, errs := bidder.MakeBids(&request, nil, &adapters.ResponseData{ + StatusCode: 200, + Body: respJson, + }) + // then + if jsonErr != nil { + t.Fatalf("Failed to serialize test bid %v: %v", bid, jsonErr) + } + if len(errs) > 0 { + t.Fatalf("Failed to make bids: %v", errs) + } + assert.Len(t, bids.Bids, 1) + + request = openrtb2.BidRequest{ + Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Audio: &openrtb2.Audio{}}), + } + // when + bids, errs = bidder.MakeBids(&request, nil, &adapters.ResponseData{ + StatusCode: 200, + Body: respJson, + }) + // then + if len(errs) > 0 { + t.Fatalf("Failed to make bids: %v", errs) + } + assert.Len(t, bids.Bids, 1) + + request = openrtb2.BidRequest{ + Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Native: &openrtb2.Native{}}), + } + // when + bids, errs = bidder.MakeBids(&request, nil, &adapters.ResponseData{ + StatusCode: 200, + Body: respJson, + }) + // then + if len(errs) > 0 { + t.Fatalf("Failed to make bids: %v", errs) + } + assert.Len(t, bids.Bids, 1) +} + func buildBidder() (adapters.Bidder, error) { return Builder( openrtb_ext.BidderAlkimi, From f970b006253a15d817ecf21d9a85f9a9d881b77b Mon Sep 17 00:00:00 2001 From: Kalidas Date: Fri, 10 Nov 2023 09:30:30 +0000 Subject: [PATCH 09/13] Changes for the review --- adapters/alkimi/alkimi.go | 6 ++---- adapters/alkimi/alkimi_test.go | 16 +--------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index d298977791f..82dd648be78 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -154,6 +154,7 @@ func (adapter *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest * bidType, err := getMediaTypeForImp(impId, imp) if err != nil { errs = append(errs, err) + continue } bidderBid := &adapters.TypedBid{ Bid: ©Bid, @@ -183,12 +184,9 @@ func getMediaTypeForImp(impId string, imps []openrtb2.Imp) (openrtb_ext.BidType, if imp.Audio != nil { return openrtb_ext.BidTypeAudio, nil } - if imp.Native != nil { - return openrtb_ext.BidTypeNative, nil - } } } - return openrtb_ext.BidTypeBanner, &errortypes.BadInput{ + return "", &errortypes.BadInput{ Message: fmt.Sprintf("Failed to find imp \"%s\"", impId), } } diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 5177b316251..175f9cede9a 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -140,7 +140,7 @@ func TestMakeBidsShouldReturnErrorIfResponseBodyContainsIncorrectImp(t *testing. if jsonErr != nil { t.Fatalf("Failed to serialize test bid %v: %v", bid, jsonErr) } - assert.Len(t, bids.Bids, 1) + assert.Len(t, bids.Bids, 0) assert.Len(t, errs, 1) } @@ -246,20 +246,6 @@ func TestMakeBidsShouldReturnBidForAllTypes(t *testing.T) { t.Fatalf("Failed to make bids: %v", errs) } assert.Len(t, bids.Bids, 1) - - request = openrtb2.BidRequest{ - Imp: append(make([]openrtb2.Imp, 1), openrtb2.Imp{ID: "impId-1", Native: &openrtb2.Native{}}), - } - // when - bids, errs = bidder.MakeBids(&request, nil, &adapters.ResponseData{ - StatusCode: 200, - Body: respJson, - }) - // then - if len(errs) > 0 { - t.Fatalf("Failed to make bids: %v", errs) - } - assert.Len(t, bids.Bids, 1) } func buildBidder() (adapters.Bidder, error) { From c39d1cbd9eda1b391c28415e4fbefe43eeeba280 Mon Sep 17 00:00:00 2001 From: Aleksandr Bogdanov Date: Wed, 15 Nov 2023 23:30:19 +0100 Subject: [PATCH 10/13] JSON tests added --- adapters/alkimi/alkimi.go | 6 +- adapters/alkimi/alkimi_test.go | 23 ++- .../alkimitest/exemplary/simple-audio.json | 140 +++++++++++++++++ .../alkimitest/exemplary/simple-banner.json | 148 ++++++++++++++++++ .../alkimitest/exemplary/simple-video.json | 147 +++++++++++++++++ .../supplemental/bad_media_type.json | 108 +++++++++++++ .../alkimitest/supplemental/bad_response.json | 101 ++++++++++++ .../alkimitest/supplemental/status-204.json | 96 ++++++++++++ .../supplemental/status-not-200.json | 101 ++++++++++++ 9 files changed, 863 insertions(+), 7 deletions(-) create mode 100644 adapters/alkimi/alkimitest/exemplary/simple-audio.json create mode 100644 adapters/alkimi/alkimitest/exemplary/simple-banner.json create mode 100644 adapters/alkimi/alkimitest/exemplary/simple-video.json create mode 100644 adapters/alkimi/alkimitest/supplemental/bad_media_type.json create mode 100644 adapters/alkimi/alkimitest/supplemental/bad_response.json create mode 100644 adapters/alkimi/alkimitest/supplemental/status-204.json create mode 100644 adapters/alkimi/alkimitest/supplemental/status-not-200.json diff --git a/adapters/alkimi/alkimi.go b/adapters/alkimi/alkimi.go index 82dd648be78..f0979c3a809 100644 --- a/adapters/alkimi/alkimi.go +++ b/adapters/alkimi/alkimi.go @@ -137,14 +137,14 @@ func (adapter *adapter) MakeBids(request *openrtb2.BidRequest, externalRequest * return nil, []error{err} } - bidCount := len(bidResp.SeatBid) - if bidCount == 0 { + seatBidCount := len(bidResp.SeatBid) + if seatBidCount == 0 { return nil, []error{&errortypes.BadServerResponse{ Message: "Empty SeatBid array", }} } - bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidCount) + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) for _, seatBid := range bidResp.SeatBid { for _, bid := range seatBid.Bid { copyBid := bid diff --git a/adapters/alkimi/alkimi_test.go b/adapters/alkimi/alkimi_test.go index 175f9cede9a..07fc8a731ab 100644 --- a/adapters/alkimi/alkimi_test.go +++ b/adapters/alkimi/alkimi_test.go @@ -1,20 +1,35 @@ package alkimi import ( - "encoding/json" - "github.com/prebid/openrtb/v19/openrtb2" - "github.com/prebid/prebid-server/v2/adapters" "testing" + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/prebid/openrtb/v19/openrtb2" "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/openrtb_ext" - "github.com/stretchr/testify/assert" + "github.com/prebid/prebid-server/v2/adapters/adapterstest" ) const ( alkimiTestEndpoint = "https://exchange.alkimi-onboarding.com/server/bid" ) +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderAlkimi, + config.Adapter{Endpoint: alkimiTestEndpoint}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}, + ) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "alkimitest", bidder) +} + func TestEndpointEmpty(t *testing.T) { _, buildErr := Builder(openrtb_ext.BidderAlkimi, config.Adapter{ Endpoint: ""}, config.Server{ExternalUrl: alkimiTestEndpoint, GvlID: 1, DataCenter: "2"}) diff --git a/adapters/alkimi/alkimitest/exemplary/simple-audio.json b/adapters/alkimi/alkimitest/exemplary/simple-audio.json new file mode 100644 index 00000000000..2e40aeba2f6 --- /dev/null +++ b/adapters/alkimi/alkimitest/exemplary/simple-audio.json @@ -0,0 +1,140 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp3" + ], + "minduration": 5, + "maxduration": 30, + "minbitrate": 32, + "maxbitrate": 128 + }, + "ext": { + "bidder": { + "token": "XXX", + "bidFloor": 0.5 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://exchange.alkimi-onboarding.com/server/bid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "audio": { + "mimes": [ + "audio/mpeg", + "audio/mp3" + ], + "minduration": 5, + "maxduration": 30, + "minbitrate": 32, + "maxbitrate": 128 + }, + "bidfloor": 0.5, + "ext": { + "bidder": { + "token": "XXX", + "bidFloor": 0.5, + "adUnitCode": "test-imp-id", + "exp": 0, + "instl": 0 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.9, + "adm": "<\/Error><\/Impression>00:00:15<\/Duration><\/Tracking><\/TrackingEvents><\/ClickThrough><\/VideoClicks><\/MediaFile><\/MediaFiles><\/Linear><\/Creative><\/Creatives><\/InLine><\/Ad><\/VAST>", + "cid": "test_cid", + "crid": "test_crid", + "ext": { + "prebid": { + "type": "audio" + } + } + } + ], + "seat": "alkimi" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.9, + "adm": "<\/Error><\/Impression>00:00:15<\/Duration><\/Tracking><\/TrackingEvents><\/ClickThrough><\/VideoClicks><\/MediaFile><\/MediaFiles><\/Linear><\/Creative><\/Creatives><\/InLine><\/Ad><\/VAST>", + "cid": "test_cid", + "crid": "test_crid", + "ext": { + "prebid": { + "type": "audio" + } + } + }, + "type": "audio" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/alkimi/alkimitest/exemplary/simple-banner.json b/adapters/alkimi/alkimitest/exemplary/simple-banner.json new file mode 100644 index 00000000000..60309f42b6a --- /dev/null +++ b/adapters/alkimi/alkimitest/exemplary/simple-banner.json @@ -0,0 +1,148 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "token": "XXX", + "bidFloor": 0.5 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://exchange.alkimi-onboarding.com/server/bid", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "bidfloor": 0.5, + "ext": { + "bidder": { + "token": "XXX", + "bidFloor": 0.5, + "adUnitCode": "test-imp-id", + "exp": 0, + "instl": 0 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.9, + "adm": "
<\/a><\/div>