From 05e06bb1b22f9a957813ec77fdbbe29947d5aa25 Mon Sep 17 00:00:00 2001 From: lm-ved <105272141+lm-ved@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:43:38 +0530 Subject: [PATCH] New Adapter: LemmaDigital (#3157) Co-authored-by: Tushar Pathare --- adapters/lemmadigital/lemmadigital.go | 114 ++++++++++++++ adapters/lemmadigital/lemmadigital_test.go | 20 +++ .../lemmadigitaltest/exemplary/banner.json | 110 +++++++++++++ .../lemmadigitaltest/exemplary/multi-imp.json | 144 ++++++++++++++++++ .../lemmadigitaltest/exemplary/video.json | 89 +++++++++++ .../supplemental/empty-imps.json | 18 +++ .../supplemental/empty-seatbid-array.json | 101 ++++++++++++ .../invalid-ld-ext-bidder-object.json | 48 ++++++ .../supplemental/invalid-ld-ext-object.json | 42 +++++ .../supplemental/invalid-response.json | 62 ++++++++ .../supplemental/status-code-bad-request.json | 62 ++++++++ .../supplemental/status-code-no-content.json | 59 +++++++ .../supplemental/status-code-other-error.json | 62 ++++++++ adapters/lemmadigital/params_test.go | 59 +++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_lemmadigital.go | 6 + static/bidder-info/lemmadigital.yaml | 14 ++ static/bidder-params/lemmadigital.json | 19 +++ 19 files changed, 1033 insertions(+) create mode 100644 adapters/lemmadigital/lemmadigital.go create mode 100644 adapters/lemmadigital/lemmadigital_test.go create mode 100644 adapters/lemmadigital/lemmadigitaltest/exemplary/banner.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/exemplary/multi-imp.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/exemplary/video.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/empty-imps.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/empty-seatbid-array.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-bidder-object.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-object.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-response.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-bad-request.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-no-content.json create mode 100644 adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-other-error.json create mode 100644 adapters/lemmadigital/params_test.go create mode 100644 openrtb_ext/imp_lemmadigital.go create mode 100644 static/bidder-info/lemmadigital.yaml create mode 100644 static/bidder-params/lemmadigital.json diff --git a/adapters/lemmadigital/lemmadigital.go b/adapters/lemmadigital/lemmadigital.go new file mode 100644 index 00000000000..3b77de52984 --- /dev/null +++ b/adapters/lemmadigital/lemmadigital.go @@ -0,0 +1,114 @@ +package lemmadigital + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "text/template" + + "github.com/prebid/openrtb/v19/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/macros" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type adapter struct { + endpoint *template.Template +} + +// Builder builds a new instance of the Lemmadigital adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + bidder := &adapter{ + endpoint: template, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + if len(request.Imp) == 0 { + return nil, []error{errors.New("Impression array should not be empty")} + } + + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(request.Imp[0].Ext, &bidderExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. Error Infomation: %s", 0, err.Error()), + }} + } + + var impExt openrtb_ext.ImpExtLemmaDigital + if err := json.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext.bidder for impression index %d. Error Infomation: %s", 0, err.Error()), + }} + } + + endpoint, err := a.buildEndpointURL(impExt) + if err != nil { + return nil, []error{err} + } + + requestJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: endpoint, + Body: requestJSON, + } + + return []*adapters.RequestData{requestData}, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := json.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidType := openrtb_ext.BidTypeBanner + if nil != request.Imp[0].Video { + bidType = openrtb_ext.BidTypeVideo + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if len(response.Cur) > 0 { + bidResponse.Currency = response.Cur + } + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + break + } + + return bidResponse, nil +} + +func (a *adapter) buildEndpointURL(params openrtb_ext.ImpExtLemmaDigital) (string, error) { + endpointParams := macros.EndpointTemplateParams{PublisherID: strconv.Itoa(params.PublisherId), + AdUnit: strconv.Itoa(params.AdId)} + return macros.ResolveMacros(a.endpoint, endpointParams) +} diff --git a/adapters/lemmadigital/lemmadigital_test.go b/adapters/lemmadigital/lemmadigital_test.go new file mode 100644 index 00000000000..0372fa81d6b --- /dev/null +++ b/adapters/lemmadigital/lemmadigital_test.go @@ -0,0 +1,20 @@ +package lemmadigital + +import ( + "testing" + + "github.com/prebid/prebid-server/adapters/adapterstest" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderLemmadigital, config.Adapter{ + Endpoint: "https://sg.ads.lemmatechnologies.com/lemma/servad?pid={{.PublisherID}}&aid={{.AdUnit}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "lemmadigitaltest", bidder) +} diff --git a/adapters/lemmadigital/lemmadigitaltest/exemplary/banner.json b/adapters/lemmadigital/lemmadigitaltest/exemplary/banner.json new file mode 100644 index 00000000000..a478380e394 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/exemplary/banner.json @@ -0,0 +1,110 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 1920, + "h": 1080 + }], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "bidfloor": 0.1 + }], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 1920, + "h": 1080 + }], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "bidfloor": 0.1 + }], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "seat": "1", + "bid": [{ + "id": "1239875642389471056", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "1", + "adm": "some-test-ad", + "adomain": ["lemmadigital.com"], + "crid": "1", + "h": 1080, + "w": 1920, + "dealid": "test_deal" + }] + }], + "bidid": "1239875642389471056", + "cur": "USD" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "1239875642389471056", + "impid": "test-imp-id", + "price": 0.5, + "adid": "1", + "adm": "some-test-ad", + "adomain": ["lemmadigital.com"], + "crid": "1", + "w": 1920, + "h": 1080, + "dealid": "test_deal" + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/exemplary/multi-imp.json b/adapters/lemmadigital/lemmadigitaltest/exemplary/multi-imp.json new file mode 100644 index 00000000000..e051b54ff95 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/exemplary/multi-imp.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 1920, + "h": 1080 + }], + "h": 1080, + "w": 1920 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "bidfloor": 0.1 + }, { + "id": "test-imp-id-2", + "banner": { + "format": [{ + "w": 1080, + "h": 1920 + }], + "h": 1920, + "w": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "bidfloor": 0.12 + }], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id", + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 1920, + "h": 1080 + }], + "h": 1080, + "w": 1920 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "bidfloor": 0.1 + }, { + "id": "test-imp-id-2", + "banner": { + "format": [{ + "w": 1080, + "h": 1920 + }], + "h": 1920, + "w": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "bidfloor": 0.12 + }], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "seat": "1", + "bid": [{ + "id": "1239875642389471056", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "1", + "adm": "some-test-ad", + "adomain": ["lemmadigital.com"], + "crid": "1", + "h": 1080, + "w": 1920, + "dealid": "test_deal" + }] + }], + "bidid": "1239875642389471056", + "cur": "USD" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "1239875642389471056", + "impid": "test-imp-id", + "price": 0.5, + "adid": "1", + "adm": "some-test-ad", + "adomain": ["lemmadigital.com"], + "crid": "1", + "w": 1920, + "h": 1080, + "dealid": "test_deal" + }, + "type": "banner" + }] + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/exemplary/video.json b/adapters/lemmadigital/lemmadigitaltest/exemplary/video.json new file mode 100644 index 00000000000..63bab75b674 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/exemplary/video.json @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id-video", + "seatbid": [{ + "seat": "1", + "bid": [{ + "id": "1239875642389471056", + "impid": "test-imp-id-video", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_video", + "h": 1080, + "w": 1920 + }] + }], + "cur": "USD" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "1239875642389471056", + "impid": "test-imp-id-video", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_video", + "w": 1920, + "h": 1080 + }, + "type": "video" + }] + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/empty-imps.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/empty-imps.json new file mode 100644 index 00000000000..e13cdcb480a --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/empty-imps.json @@ -0,0 +1,18 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "imp": [], + "site": { + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [{ + "value": "Impression array should not be empty", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/empty-seatbid-array.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/empty-seatbid-array.json new file mode 100644 index 00000000000..c88e0fa7861 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/empty-seatbid-array.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "app": { + "bundle": "com.ld.test", + "cat": [ + "IAB-1" + ], + "domain": "ld.com", + "id": "1", + "name": "LD Test", + "publisher": { + "id": "1" + } + }, + "device": { + "dnt": 0, + "ip": "0.0.0.0", + "language": "en", + "ua": "user-agent" + }, + "id": "test-request-id-video", + "imp": [{ + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "id": "test-imp-id-video", + "video": { + "h": 1080, + "mimes": [ + "video/mp4" + ], + "protocols": [ + 1 + ], + "w": 1920 + } + }], + "tmax": 1000 + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "app": { + "bundle": "com.ld.test", + "cat": [ + "IAB-1" + ], + "domain": "ld.com", + "id": "1", + "name": "LD Test", + "publisher": { + "id": "1" + } + }, + "device": { + "dnt": 0, + "ip": "0.0.0.0", + "language": "en", + "ua": "user-agent" + }, + "id": "test-request-id-video", + "imp": [{ + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + }, + "id": "test-imp-id-video", + "video": { + "h": 1080, + "mimes": [ + "video/mp4" + ], + "protocols": [ + 1 + ], + "w": 1920 + } + }], + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-1", + "seatbid": [], + "cur": "USD" + } + } + }], + "expectedBidResponses": [{ + "currency": "USD", + "bids": [] +}] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-bidder-object.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-bidder-object.json new file mode 100644 index 00000000000..ba46d76b598 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-bidder-object.json @@ -0,0 +1,48 @@ +{ + "expectedMakeRequestsErrors": [{ + "value": "Invalid imp.ext.bidder for impression index 0. Error Infomation: json: cannot unmarshal string into Go struct field ImpExtLemmaDigital.pid of type int", + "comparison": "literal" + }], + "mockBidRequest": { + "app": { + "bundle": "com.ld.test", + "cat": [ + "IAB-1" + ], + "domain": "ld.com", + "id": "1", + "name": "LD Test", + "publisher": { + "id": "1" + } + }, + "device": { + "dnt": 0, + "ip": "0.0.0.0", + "language": "en", + "ua": "user-agent" + }, + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "h": 1080, + "mimes": [ + "video/mp4" + ], + "protocols": [ + 1 + ], + "w": 1920 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": "1" + } + } + }], + "tmax": 1000 + }, + "httpCalls": [] + } \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-object.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-object.json new file mode 100644 index 00000000000..4d3d795c185 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-ld-ext-object.json @@ -0,0 +1,42 @@ +{ + "expectedMakeRequestsErrors": [{ + "value": "Invalid imp.ext for impression index 0. Error Infomation: unexpected end of JSON input", + "comparison": "literal" + }], + "mockBidRequest": { + "app": { + "bundle": "com.ld.test", + "cat": [ + "IAB-1" + ], + "domain": "ld.com", + "id": "1", + "name": "LD Test", + "publisher": { + "id": "1" + } + }, + "device": { + "dnt": 0, + "ip": "0.0.0.0", + "language": "en", + "ua": "user-agent" + }, + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "h": 1080, + "mimes": [ + "video/mp4" + ], + "protocols": [ + 1 + ], + "w": 1920 + } + }], + "tmax": 1000 + }, + "httpCalls": [] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-response.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-response.json new file mode 100644 index 00000000000..036d35fb345 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/invalid-response.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": "" + } + }], + "expectedMakeBidsErrors": [{ + "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-bad-request.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-bad-request.json new file mode 100644 index 00000000000..37ebea4b7be --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-bad-request.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 400 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-no-content.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-no-content.json new file mode 100644 index 00000000000..7c4813df43a --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-no-content.json @@ -0,0 +1,59 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 204 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-other-error.json b/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-other-error.json new file mode 100644 index 00000000000..047dc4efd83 --- /dev/null +++ b/adapters/lemmadigital/lemmadigitaltest/supplemental/status-code-other-error.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "https://sg.ads.lemmatechnologies.com/lemma/servad?pid=1&aid=1", + "body": { + "id": "test-request-id-video", + "imp": [{ + "id": "test-imp-id-video", + "video": { + "mimes": ["video/mp4"], + "protocols": [1], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "aid": 1, + "pid": 1 + } + } + }], + "site": { + "publisher": { + "id": "1" + } + } + } + }, + "mockResponse": { + "status": 503 + } + }], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [{ + "value": "Unexpected status code: 503. Run with request.debug = 1 for more info", + "comparison": "literal" + }] +} \ No newline at end of file diff --git a/adapters/lemmadigital/params_test.go b/adapters/lemmadigital/params_test.go new file mode 100644 index 00000000000..57bc7d83e79 --- /dev/null +++ b/adapters/lemmadigital/params_test.go @@ -0,0 +1,59 @@ +package lemmadigital + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +// Tests for static/bidder-params/lemmadigital.json + +// Tests whether the schema supports the intended params. +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 _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderLemmadigital, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected params: %s \n Error: %s", validParam, err) + } + } +} + +// Tests whether the schema rejects unsupported imp.ext fields. +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 _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderLemmadigital, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed invalid/unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"pid":1, "aid": 1}`, + `{"pid":2147483647, "aid": 2147483647}`, +} + +var invalidParams = []string{ + ``, + `null`, + `false`, + `0`, + `0.0`, + `[]`, + `{}`, + `{"pid":1}`, + `{"aid":1}`, + `{"pid":"1","aid":1}`, + `{"pid":1.0,"aid":"1"}`, + `{"pid":"1","aid":"1"}`, + `{"pid":false,"aid":true}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index d8ab16c1d61..25630fed414 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -103,6 +103,7 @@ import ( "github.com/prebid/prebid-server/adapters/kidoz" "github.com/prebid/prebid-server/adapters/kiviads" "github.com/prebid/prebid-server/adapters/krushmedia" + "github.com/prebid/prebid-server/adapters/lemmadigital" "github.com/prebid/prebid-server/adapters/liftoff" "github.com/prebid/prebid-server/adapters/limelightDigital" lmkiviads "github.com/prebid/prebid-server/adapters/lm_kiviads" @@ -304,6 +305,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderKiviads: kiviads.Builder, openrtb_ext.BidderLmKiviads: lmkiviads.Builder, openrtb_ext.BidderKrushmedia: krushmedia.Builder, + openrtb_ext.BidderLemmadigital: lemmadigital.Builder, openrtb_ext.BidderLiftoff: liftoff.Builder, openrtb_ext.BidderLimelightDigital: limelightDigital.Builder, openrtb_ext.BidderLockerDome: lockerdome.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 635f17cd58f..744c7fad3fe 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -131,6 +131,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderKiviads, BidderLmKiviads, BidderKrushmedia, + BidderLemmadigital, BidderLiftoff, BidderLimelightDigital, BidderLockerDome, @@ -422,6 +423,7 @@ const ( BidderKiviads BidderName = "kiviads" BidderLmKiviads BidderName = "lm_kiviads" BidderKrushmedia BidderName = "krushmedia" + BidderLemmadigital BidderName = "lemmadigital" BidderLiftoff BidderName = "liftoff" BidderLimelightDigital BidderName = "limelightDigital" BidderLockerDome BidderName = "lockerdome" diff --git a/openrtb_ext/imp_lemmadigital.go b/openrtb_ext/imp_lemmadigital.go new file mode 100644 index 00000000000..c691dd173d9 --- /dev/null +++ b/openrtb_ext/imp_lemmadigital.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtLemmaDigital struct { + PublisherId int `json:"pid"` + AdId int `json:"aid"` +} diff --git a/static/bidder-info/lemmadigital.yaml b/static/bidder-info/lemmadigital.yaml new file mode 100644 index 00000000000..535c91ffa77 --- /dev/null +++ b/static/bidder-info/lemmadigital.yaml @@ -0,0 +1,14 @@ +endpoint: "https://sg.ads.lemmatechnologies.com/lemma/servad?pid={{.PublisherID}}&aid={{.AdUnit}}" +maintainer: + email: support@lemmatechnologies.com +endpointCompression: gzip +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video \ No newline at end of file diff --git a/static/bidder-params/lemmadigital.json b/static/bidder-params/lemmadigital.json new file mode 100644 index 00000000000..be4a89edd7a --- /dev/null +++ b/static/bidder-params/lemmadigital.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Lemma Adapter Params", + "description": "A schema which validates params accepted by the Lemma adapter", + "type": "object", + + "properties": { + "pid": { + "type": "integer", + "description": "Publisher ID" + }, + "aid": { + "type": "integer", + "description": "Ad ID" + } + }, + + "required": ["pid", "aid"] +} \ No newline at end of file