diff --git a/adapters/roundhouseads/params_test.go b/adapters/roundhouseads/params_test.go new file mode 100644 index 0000000000..674feae96c --- /dev/null +++ b/adapters/roundhouseads/params_test.go @@ -0,0 +1,53 @@ +package roundhouseads + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/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-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderRoundhouseads, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Roundhouseads params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the Roundhouseads schema rejects all the imp.ext fields we don't support. +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderRoundhouseads, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"publisherId": "123456"}`, + `{"publisherId": "pub-123456"}`, + `{"publisherId": "publisherIDAllString"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"publisherId": 123456}`, + `{"publisherId": 0}`, +} diff --git a/adapters/roundhouseads/roundhouseads.go b/adapters/roundhouseads/roundhouseads.go new file mode 100644 index 0000000000..ab2d0ba0e8 --- /dev/null +++ b/adapters/roundhouseads/roundhouseads.go @@ -0,0 +1,196 @@ +package roundhouseads + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "regexp" + "text/template" + + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/macros" + "github.com/prebid/prebid-server/v3/openrtb_ext" + + "github.com/prebid/openrtb/v20/openrtb2" +) + +const PREBID_INTEGRATION_TYPE = "1" + +type adapter struct { + bidderEndpoint string +} + +type ExtImpBidderRoundhouseads struct { + adapters.ExtImpBidder +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + pubID, err := getPublisherId(request.Imp) + + if err != nil { + return nil, []error{err} + } + + modifiedImps := make([]openrtb2.Imp, 0, len(request.Imp)) + + for _, imp := range request.Imp { + + if imp.Banner != nil { + if len(imp.Banner.Format) > 0 { + firstFormat := imp.Banner.Format[0] + bannerCopy := *imp.Banner + bannerCopy.H = &firstFormat.H + bannerCopy.W = &firstFormat.W + imp.Banner = &bannerCopy + + } + } + + modifiedImps = append(modifiedImps, imp) + } + + request.Imp = modifiedImps + + if request.Site != nil { + siteCopy := *request.Site + if siteCopy.Publisher != nil { + publisherCopy := *siteCopy.Publisher + if pubID != "" { + publisherCopy.ID = pubID + } + siteCopy.Publisher = &publisherCopy + } else { + siteCopy.Publisher = &openrtb2.Publisher{ID: pubID} + } + request.Site = &siteCopy + } else if request.App != nil { + appCopy := *request.App + if appCopy.Publisher != nil { + publisherCopy := *appCopy.Publisher + if pubID != "" { + publisherCopy.ID = pubID + } + appCopy.Publisher = &publisherCopy + } else { + appCopy.Publisher = &openrtb2.Publisher{ID: pubID} + } + request.App = &appCopy + } + + errs := make([]error, 0, len(request.Imp)) + reqJSON, err := json.Marshal(request) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + headers.Add("x-integration-type", PREBID_INTEGRATION_TYPE) + return []*adapters.RequestData{{ + Method: "POST", + Uri: a.bidderEndpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }}, errs +} + +func getPublisherId(impressions []openrtb2.Imp) (string, error) { + for _, imp := range impressions { + + var bidderExt ExtImpBidderRoundhouseads + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return "", err + } + + var roundhouseadsExt openrtb_ext.ExtImpRoundhouseads + if err := json.Unmarshal(bidderExt.Bidder, &roundhouseadsExt); err != nil { + return "", err + } + + if roundhouseadsExt.PublisherId != "" { + return roundhouseadsExt.PublisherId, nil + } + } + return "", nil +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return adapters.NewBidderResponse(), nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var bidResponse openrtb2.BidResponse + if err := json.Unmarshal(response.Body, &bidResponse); err != nil { + return nil, []error{err} + } + + bidderResponse := adapters.NewBidderResponse() + bidderResponse.Currency = bidResponse.Cur + + for _, seatBid := range bidResponse.SeatBid { + for _, bid := range seatBid.Bid { + bid := bid + + bidType, err := getBidType(bid.MType) + + if err != nil { + return nil, []error{err} + } + + b := &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + } + bidderResponse.Bids = append(bidderResponse.Bids, b) + } + } + + return bidderResponse, nil +} + +func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) { + switch markupType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + default: + return "", fmt.Errorf("unsupported mtype: %d", markupType) + } +} + +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) + } + + if len(config.ExtraAdapterInfo) > 0 { + isValidEndpoint, err := regexp.Match("([a-z]+)$", []byte(config.ExtraAdapterInfo)) + if !isValidEndpoint || err != nil { + return nil, errors.New("ExtraAdapterInfo must be a simple string provided by Roundhouseads") + } + } + + urlParams := macros.EndpointTemplateParams{SupplyId: config.ExtraAdapterInfo} + bidderEndpoint, err := macros.ResolveMacros(template, urlParams) + + if err != nil { + return nil, fmt.Errorf("unable to resolve endpoint macros: %v", err) + } + + return &adapter{ + bidderEndpoint: bidderEndpoint, + }, nil +} diff --git a/adapters/roundhouseads/roundhouseads_test.go b/adapters/roundhouseads/roundhouseads_test.go new file mode 100644 index 0000000000..e6e7872a3d --- /dev/null +++ b/adapters/roundhouseads/roundhouseads_test.go @@ -0,0 +1,385 @@ +package roundhouseads + +import ( + "encoding/json" + "net/http" + "testing" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderRoundhouseads, config.Adapter{ + Endpoint: "{{Malformed}}"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} + +func TestBadConfig(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderRoundhouseads, config.Adapter{ + Endpoint: `http://it.doesnt.matter/bid`, + ExtraAdapterInfo: "12365217635", + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} + +func TestCorrectConfig(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderRoundhouseads, config.Adapter{ + Endpoint: `http://it.doesnt.matter/bid`, + ExtraAdapterInfo: `abcde`, + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.NoError(t, buildErr) + assert.NotNil(t, bidder) +} + +func TestEmptyConfig(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderRoundhouseads, config.Adapter{ + Endpoint: `https://roundhouseads.com/openrtb2`, + ExtraAdapterInfo: `roundhouseads`, + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.NoError(t, buildErr) + assert.NotNil(t, bidder) +} + +func TestJsonSamples(t *testing.T) { + bidder, err := Builder( + openrtb_ext.BidderRoundhouseads, + config.Adapter{Endpoint: "https://roundhouseads.com/openrtb2", ExtraAdapterInfo: "roundhouseads"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "1"}, + ) + assert.Nil(t, err) + adapterstest.RunJSONBidderTest(t, "roundhouseadstest", bidder) +} + +func TestGetBidType(t *testing.T) { + type args struct { + markupType openrtb2.MarkupType + } + tests := []struct { + name string + args args + markupType openrtb2.MarkupType + expectedBidTypeId openrtb_ext.BidType + wantErr bool + }{ + { + name: "banner", + args: args{ + markupType: openrtb2.MarkupBanner, + }, + expectedBidTypeId: openrtb_ext.BidTypeBanner, + wantErr: false, + }, + { + name: "video", + args: args{ + markupType: openrtb2.MarkupVideo, + }, + expectedBidTypeId: openrtb_ext.BidTypeVideo, + wantErr: false, + }, + { + name: "native", + args: args{ + markupType: openrtb2.MarkupNative, + }, + expectedBidTypeId: openrtb_ext.BidTypeNative, + wantErr: false, + }, + { + name: "invalid", + args: args{ + markupType: -1, + }, + expectedBidTypeId: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bidType, err := getBidType(tt.args.markupType) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.expectedBidTypeId, bidType) + }) + } +} + +func TestGetPublisherId(t *testing.T) { + type args struct { + impressions []openrtb2.Imp + } + tests := []struct { + name string + args args + expectedPublisherId string + wantErr bool + }{ + { + name: "valid_publisher_Id", + args: args{ + impressions: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + Ext: json.RawMessage(`{"bidder":{"publisherId":"1"}}`), + }, + }, + }, + expectedPublisherId: "1", + wantErr: false, + }, + { + name: "multiple_valid_publisher_Id", + args: args{ + impressions: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + Ext: json.RawMessage(`{"bidder":{"publisherId":"1"}}`), + }, + { + Video: &openrtb2.Video{}, + Ext: json.RawMessage(`{"bidder":{"publisherId":"2"}}`), + }, + }, + }, + expectedPublisherId: "1", + wantErr: false, + }, + { + name: "not_publisherId_present", + args: args{ + impressions: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + Ext: json.RawMessage(`{"bidder":{}}`), + }, + }, + }, + expectedPublisherId: "", + wantErr: false, + }, + { + name: "nil_publisherId_present", + args: args{ + impressions: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + Ext: json.RawMessage(`{"bidder":{"publisherId":""}}`), + }, + }, + }, + expectedPublisherId: "", + wantErr: false, + }, + { + name: "no_impressions", + args: args{ + impressions: []openrtb2.Imp{}, + }, + expectedPublisherId: "", + wantErr: false, + }, + { + name: "invalid_bidder_object", + args: args{ + impressions: []openrtb2.Imp{ + { + Video: &openrtb2.Video{}, + Ext: json.RawMessage(`{"bidder":{"doesnotexistprop":""}}`), + }, + }, + }, + expectedPublisherId: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + publisherId, err := getPublisherId(tt.args.impressions) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, tt.expectedPublisherId, publisherId) + }) + } +} + +func TestRoundhouseadsAdapter_MakeRequests(t *testing.T) { + type fields struct { + URI string + } + type args struct { + request *openrtb2.BidRequest + reqInfo *adapters.ExtraRequestInfo + } + tests := []struct { + name string + fields fields + args args + expectedReqData []*adapters.RequestData + wantErr bool + }{ + { + name: "invalid_bidderparams", + args: args{ + request: &openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"bidderparams":{:"123"}}}`)}, + }, + wantErr: true, + }, + { + name: "request_with_App", + args: args{ + request: &openrtb2.BidRequest{ + App: &openrtb2.App{}, + Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":"123"}}}`), + }, + }, + wantErr: false, + }, + { + name: "request_with_App_and_publisher", + args: args{ + request: &openrtb2.BidRequest{ + App: &openrtb2.App{Publisher: &openrtb2.Publisher{}}, + Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":"123"}}}`), + }, + }, + wantErr: false, + }, + { + name: "request_with_Site", + args: args{ + request: &openrtb2.BidRequest{ + Site: &openrtb2.Site{}, + Ext: json.RawMessage(`{"prebid":{"bidderparams":{"wrapper":"123"}}}`), + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &adapter{ + bidderEndpoint: tt.fields.URI, + } + gotReqData, gotErr := a.MakeRequests(tt.args.request, tt.args.reqInfo) + assert.Equal(t, tt.wantErr, len(gotErr) != 0) + if tt.wantErr == false { + assert.NotNil(t, gotReqData) + } + }) + } +} + +func TestRoundhouseadsAdapter_MakeBids(t *testing.T) { + type fields struct { + URI string + } + type args struct { + internalRequest *openrtb2.BidRequest + externalRequest *adapters.RequestData + response *adapters.ResponseData + } + tests := []struct { + name string + fields fields + args args + wantErr []error + wantResp *adapters.BidderResponse + }{ + { + name: "happy_path_valid_response_with_all_bid_params", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"mtype": 1, "id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["roundhouseads.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + }, + }, + wantErr: nil, + wantResp: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "7706636740145184841", + ImpID: "test-imp-id", + Price: 0.500000, + AdID: "29681110", + AdM: "some-test-ad", + ADomain: []string{"roundhouseads.com"}, + CrID: "29681110", + H: 250, + W: 300, + DealID: "testdeal", + Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}`), + MType: openrtb2.MarkupBanner, + }, + BidType: openrtb_ext.BidTypeBanner, + }, + }, + Currency: "USD", + }, + }, + { + name: "ignore_invalid_prebiddealpriority", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"mtype": 2, "id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["roundhouseads.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + }, + }, + wantErr: nil, + wantResp: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "7706636740145184841", + ImpID: "test-imp-id", + Price: 0.500000, + AdID: "29681110", + AdM: "some-test-ad", + ADomain: []string{"roundhouseads.com"}, + CrID: "29681110", + H: 250, + W: 300, + DealID: "testdeal", + Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}`), + MType: openrtb2.MarkupVideo, + }, + BidType: openrtb_ext.BidTypeVideo, + }, + }, + Currency: "USD", + }, + }, + { + name: "no_content_response", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusNoContent, + Body: nil, + }, + }, + wantErr: nil, + wantResp: adapters.NewBidderResponse(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &adapter{ + bidderEndpoint: tt.fields.URI, + } + gotResp, gotErr := a.MakeBids(tt.args.internalRequest, tt.args.externalRequest, tt.args.response) + assert.Equal(t, tt.wantErr, gotErr, gotErr) + assert.Equal(t, tt.wantResp, gotResp) + }) + } +} diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-inapp.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-inapp.json new file mode 100644 index 0000000000..026f437695 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-inapp.json @@ -0,0 +1,143 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "this_id_will_be_replaced" + } + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 100, + "h": 150 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner", + "networkName": "Roundhouseads" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner", + "networkName": "Roundhouseads" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-multiple-bids-and-formats.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-multiple-bids-and-formats.json new file mode 100644 index 0000000000..ea81f950ce --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-multiple-bids-and-formats.json @@ -0,0 +1,230 @@ +{ + "mockBidRequest": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 500, + "h": 300 + } + ], + "w": 55, + "h": 33 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 900, + "h": 450 + }, + { + "w": 500, + "h": 300 + } + ], + "w": 88, + "h": 99 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 500, + "h": 300 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 900, + "h": 450 + }, + { + "w": 500, + "h": 300 + } + ], + "w": 900, + "h": 450 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id", "test-imp-id2"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + }, + { + "bid": [ + { + "id": "test-slot-id2", + "impid": "test-imp-id2", + "price": 0.5, + "crid": "creative-123", + "adm": "", + "w": 900, + "h": 450, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "test-slot-id2", + "impid": "test-imp-id2", + "price": 0.5, + "crid": "creative-123", + "adm": "", + "w": 900, + "h": 450, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-multiple-bids.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-multiple-bids.json new file mode 100644 index 0000000000..562fa18d9f --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner-multiple-bids.json @@ -0,0 +1,214 @@ +{ + "mockBidRequest": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id-multiple-bids", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id", "test-imp-id2"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + }, + { + "bid": [ + { + "id": "test-slot-id2", + "impid": "test-imp-id2", + "price": 0.5, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "test-slot-id2", + "impid": "test-imp-id2", + "price": 0.5, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner.json new file mode 100644 index 0000000000..da68ded315 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-banner.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 100, + "h": 150 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-empty-publisherId.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-empty-publisherId.json new file mode 100644 index 0000000000..62033c70d2 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-empty-publisherId.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "did_not_override" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "did_not_override" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-multi-type-banner.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-multi-type-banner.json new file mode 100644 index 0000000000..952dc37b85 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-multi-type-banner.json @@ -0,0 +1,150 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "banner" + } + }, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-multi-type-video.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-multi-type-video.json new file mode 100644 index 0000000000..42bca566f9 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-multi-type-video.json @@ -0,0 +1,150 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 300, + "h": 250 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + }, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + }, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-native.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-native.json new file mode 100644 index 0000000000..dc5f2f4b8d --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-native.json @@ -0,0 +1,114 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "native" + } + }, + "mtype": 4 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "native" + } + }, + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/exemplary/simple-video.json b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-video.json new file mode 100644 index 0000000000..f50d72aac2 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/exemplary/simple-video.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com" + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "pbs-local/preroll", + "video": { + "minduration": 0, + "maxduration": 60, + "api": [1, 2], + "mimes": [ + "video/mp4", + "video/webm", + "application/javascript" + ], + "placement": 1, + "protocols": [2, 3, 4, 5, 6], + "w": 300, + "h": 250, + "playbackmethod": [1, 2, 3, 4, 5, 6], + "plcmt": 1, + "skip": 1 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "site": { + "id": "site-id", + "page": "roundhouseads.com", + "publisher": { + "id": "123456" + } + }, + "device": { + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "pbs-local/preroll", + "video": { + "maxduration": 60, + "api": [1, 2], + "mimes": [ + "video/mp4", + "video/webm", + "application/javascript" + ], + "placement": 1, + "protocols": [2, 3, 4, 5, 6], + "w": 300, + "h": 250, + "playbackmethod": [1, 2, 3, 4, 5, 6], + "plcmt": 1, + "skip": 1 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + }, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "some-test-ad-vast", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "video" + } + }, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/supplemental/200-response-from-target.json b/adapters/roundhouseads/roundhouseadstest/supplemental/200-response-from-target.json new file mode 100644 index 0000000000..6f473a06e2 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/supplemental/200-response-from-target.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unexpected end of JSON input", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/supplemental/204-response-from-target.json b/adapters/roundhouseads/roundhouseadstest/supplemental/204-response-from-target.json new file mode 100644 index 0000000000..1f5d2c6513 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/supplemental/204-response-from-target.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ] + } \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/supplemental/400-response-from-target.json b/adapters/roundhouseads/roundhouseadstest/supplemental/400-response-from-target.json new file mode 100644 index 0000000000..017d5a4aed --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/supplemental/400-response-from-target.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 400 + } + } + ], + "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/roundhouseads/roundhouseadstest/supplemental/500-response-from-target.json b/adapters/roundhouseads/roundhouseadstest/supplemental/500-response-from-target.json new file mode 100644 index 0000000000..bf6742edf1 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/supplemental/500-response-from-target.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle" + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "123456" + } + }, + "device": { + "ifa": "test-ifa-123456", + "ip": "91.199.242.236", + "ua": "random user agent", + "os": "android" + }, + "regs": { + "ext": { + "us_privacy": "1YYY" + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/supplemental/invalid-mtype.json b/adapters/roundhouseads/roundhouseadstest/supplemental/invalid-mtype.json new file mode 100644 index 0000000000..a001aef769 --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/supplemental/invalid-mtype.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://roundhouseads.com/openrtb2", + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Integration-Type": ["1"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "" + }, + "ext": { + "bidder": { + "publisherId": "123456" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "currency": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "test-slot-id", + "impid": "test-imp-id", + "price": 0.1, + "crid": "creative-123", + "adm": "", + "h": 250, + "w": 300, + "ext": { + "prebid": { + "type": "native" + } + }, + "mtype": -1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "unsupported mtype: -1", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/roundhouseads/roundhouseadstest/supplemental/invalid-publisher.json b/adapters/roundhouseads/roundhouseadstest/supplemental/invalid-publisher.json new file mode 100644 index 0000000000..dd8110906c --- /dev/null +++ b/adapters/roundhouseads/roundhouseadstest/supplemental/invalid-publisher.json @@ -0,0 +1,44 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "test.app.bundle", + "publisher": { + "id": "this_id_will_be_replaced" + } + }, + "device": { + "ifa": "test-ifa-123456", + "os": "android", + "ip": "91.199.242.236", + "ua": "random user agent" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": 123456 + } + } + } + ] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "json: cannot unmarshal number into Go struct field ExtImpRoundhouseads.publisherId of type string", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 67e28286f0..3000c612c2 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -168,6 +168,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/richaudience" "github.com/prebid/prebid-server/v3/adapters/rise" "github.com/prebid/prebid-server/v3/adapters/roulax" + "github.com/prebid/prebid-server/v3/adapters/roundhouseads" "github.com/prebid/prebid-server/v3/adapters/rtbhouse" "github.com/prebid/prebid-server/v3/adapters/rubicon" salunamedia "github.com/prebid/prebid-server/v3/adapters/sa_lunamedia" @@ -400,6 +401,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderRichaudience: richaudience.Builder, openrtb_ext.BidderRise: rise.Builder, openrtb_ext.BidderRoulax: roulax.Builder, + openrtb_ext.BidderRoundhouseads: roundhouseads.Builder, openrtb_ext.BidderRTBHouse: rtbhouse.Builder, openrtb_ext.BidderRubicon: rubicon.Builder, openrtb_ext.BidderSeedingAlliance: seedingAlliance.Builder, diff --git a/go.mod b/go.mod index e844fe5bf2..fe1597fc57 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 retract v3.0.0 // Forgot to update major version in import path and module name require ( + github.com/51Degrees/device-detection-go/v4 v4.4.35 github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/IABTechLab/adscert v0.34.0 github.com/NYTimes/gziphandler v1.1.1 @@ -32,8 +33,11 @@ require ( github.com/prometheus/client_model v0.2.0 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/rs/cors v1.11.0 + github.com/spf13/cast v1.5.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.8.1 + github.com/tidwall/gjson v1.17.1 + github.com/tidwall/sjson v1.2.5 github.com/vrischmann/go-metrics-influxdb v0.1.1 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yudai/gojsondiff v1.0.0 @@ -45,7 +49,6 @@ require ( ) require ( - github.com/51Degrees/device-detection-go/v4 v4.4.35 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -65,15 +68,12 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/spf13/afero v1.8.2 // indirect - github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.3.0 // indirect - github.com/tidwall/gjson v1.17.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - github.com/tidwall/sjson v1.2.5 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index f7706ce5c2..d9d78f2d71 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -186,6 +186,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderRichaudience, BidderRise, BidderRoulax, + BidderRoundhouseads, BidderRTBHouse, BidderRubicon, BidderSeedingAlliance, @@ -515,6 +516,7 @@ const ( BidderRichaudience BidderName = "richaudience" BidderRise BidderName = "rise" BidderRoulax BidderName = "roulax" + BidderRoundhouseads BidderName = "roundhouseads" BidderRTBHouse BidderName = "rtbhouse" BidderRubicon BidderName = "rubicon" BidderSeedingAlliance BidderName = "seedingAlliance" diff --git a/openrtb_ext/imp_roundhouseads.go b/openrtb_ext/imp_roundhouseads.go new file mode 100644 index 0000000000..3102d13612 --- /dev/null +++ b/openrtb_ext/imp_roundhouseads.go @@ -0,0 +1,8 @@ +package openrtb_ext + +// ExtImpRoundhouseads defines the contract for bidrequest.imp[i].ext +// PublisherId is a mandatory parameter for the Roundhouseads bidder. + +type ExtImpRoundhouseads struct { + PublisherId string `json:"publisherId"` +} diff --git a/static/bidder-info/roundhouseads.yaml b/static/bidder-info/roundhouseads.yaml new file mode 100644 index 0000000000..3be74ff3f7 --- /dev/null +++ b/static/bidder-info/roundhouseads.yaml @@ -0,0 +1,26 @@ +endpoint: "http://pbsv4-env.eba-qx2kfrgj.us-east-1.elasticbeanstalk.com/openrtb2/auction" + +maintainer: + email: "info@roundhouseads.com" +#gvlVendorID: 42 #need assigned ID +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + # Roundhouseads supports user syncing, but requires configuration by the host. Contact a technical account manager + # or this bidder directly at the email address in this file to ask about enabling user sync. + endpointCompression: gzip + supports: + - redirect + - iframe +openrtb: + gpp-supported: true + diff --git a/static/bidder-params/roundhouseads.json b/static/bidder-params/roundhouseads.json new file mode 100644 index 0000000000..8c64cc99cd --- /dev/null +++ b/static/bidder-params/roundhouseads.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Roundhouseads Adapter Params", + "description": "A schema which validates params accepted by the Roundhouseads adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "description": "An ID which identifies the publisher" + } + }, + "required": ["publisherId"] +} \ No newline at end of file