From 135e842af3ae9ac1797357a9105646a6f990101c Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Mon, 17 Feb 2020 16:40:59 +0200 Subject: [PATCH 1/4] admixer-adapter done --- adapters/admixer/admixer.go | 165 ++++++++++++++++++ adapters/admixer/admixer_test.go | 10 ++ .../exemplary/optional-params.json | 47 +++++ .../admixertest/exemplary/simple-app-audio | 89 ++++++++++ .../exemplary/simple-app-banner.json | 101 +++++++++++ .../admixertest/exemplary/simple-app-native | 90 ++++++++++ .../admixertest/exemplary/simple-app-video | 111 ++++++++++++ .../exemplary/simple-site-audio.json | 89 ++++++++++ .../exemplary/simple-site-banner.json | 101 +++++++++++ .../exemplary/simple-site-native.json | 90 ++++++++++ .../exemplary/simple-site-video.json | 111 ++++++++++++ .../admixertest/params/race/audio.json | 5 + .../admixertest/params/race/banner.json | 5 + .../admixertest/params/race/native.json | 5 + .../admixertest/params/race/video.json | 5 + adapters/admixer/params_test.go | 57 ++++++ adapters/admixer/usersync.go | 11 ++ adapters/admixer/usersync_test.go | 34 ++++ config/config.go | 2 + exchange/adapter_map.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_admixer.go | 7 + static/bidder-info/admixer.yaml | 15 ++ static/bidder-params/admixer.json | 25 +++ usersync/usersyncers/syncer.go | 2 + 25 files changed, 1181 insertions(+) create mode 100644 adapters/admixer/admixer.go create mode 100644 adapters/admixer/admixer_test.go create mode 100644 adapters/admixer/admixertest/exemplary/optional-params.json create mode 100644 adapters/admixer/admixertest/exemplary/simple-app-audio create mode 100644 adapters/admixer/admixertest/exemplary/simple-app-banner.json create mode 100644 adapters/admixer/admixertest/exemplary/simple-app-native create mode 100644 adapters/admixer/admixertest/exemplary/simple-app-video create mode 100644 adapters/admixer/admixertest/exemplary/simple-site-audio.json create mode 100644 adapters/admixer/admixertest/exemplary/simple-site-banner.json create mode 100644 adapters/admixer/admixertest/exemplary/simple-site-native.json create mode 100644 adapters/admixer/admixertest/exemplary/simple-site-video.json create mode 100644 adapters/admixer/admixertest/params/race/audio.json create mode 100644 adapters/admixer/admixertest/params/race/banner.json create mode 100644 adapters/admixer/admixertest/params/race/native.json create mode 100644 adapters/admixer/admixertest/params/race/video.json create mode 100644 adapters/admixer/params_test.go create mode 100644 adapters/admixer/usersync.go create mode 100644 adapters/admixer/usersync_test.go create mode 100644 openrtb_ext/imp_admixer.go create mode 100644 static/bidder-info/admixer.yaml create mode 100644 static/bidder-params/admixer.json diff --git a/adapters/admixer/admixer.go b/adapters/admixer/admixer.go new file mode 100644 index 00000000000..7257014dd21 --- /dev/null +++ b/adapters/admixer/admixer.go @@ -0,0 +1,165 @@ +package admixer + +import ( + "encoding/json" + "fmt" + "github.com/mxmCherry/openrtb" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" + "net/http" +) + +type AdmixerAdapter struct { + endpoint string +} + +func NewAdmixerBidder(endpoint string) *AdmixerAdapter { + return &AdmixerAdapter{endpoint: endpoint} +} + +type admixerImpExt struct { + CustomParams map[string]interface{} `json:"customParams"` +} + +func (a *AdmixerAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) (requests []*adapters.RequestData, errors []error) { + rq, errs := a.makeRequest(request) + if len(errs) > 0 { + errors = append(errors, errs...) + return + } + if request != nil { + requests = append(requests, rq) + } + + return +} + +func (a *AdmixerAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, []error) { + var errs []error + var validImps []openrtb.Imp + + for _, imp := range request.Imp { + if err := preprocess(&imp); err != nil { + errs = append(errs, err) + continue + } + validImps = append(validImps, imp) + } + + if len(validImps) == 0 { + return nil, errs + } + + request.Imp = validImps + + 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") + return &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + }, errs +} + +func preprocess(imp *openrtb.Imp) error { + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return &errortypes.BadInput{ + Message: err.Error(), + } + } + + var admixerExt openrtb_ext.ExtImpAdmixer + if err := json.Unmarshal(bidderExt.Bidder, &admixerExt); err != nil { + return &errortypes.BadInput{ + Message: err.Error(), + } + } + + imp.TagID = admixerExt.ZoneId + imp.BidFloor = admixerExt.CustomBidFloor + + imp.Ext = nil + + if admixerExt.CustomParams != nil { + if admixerExt.CustomParams != nil { + impExt := admixerImpExt{ + CustomParams: admixerExt.CustomParams, + } + var err error + if imp.Ext, err = json.Marshal(impExt); err != nil { + return &errortypes.BadInput{ + Message: err.Error(), + } + } + } + } + + return nil +} + +func (a *AdmixerAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + + if response.StatusCode == http.StatusBadRequest { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + if response.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + var bidResp openrtb.BidResponse + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + //additional no content check + if len(bidResp.SeatBid) == 0 || len(bidResp.SeatBid[0].Bid) == 0 { + return nil, nil + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp), + }) + } + } + return bidResponse, nil +} + +func getMediaTypeForImp(impID string, imps []openrtb.Imp) openrtb_ext.BidType { + for _, imp := range imps { + if imp.ID == impID { + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner + } else if imp.Video != nil { + return openrtb_ext.BidTypeVideo + } else if imp.Native != nil { + return openrtb_ext.BidTypeNative + } else if imp.Audio != nil { + return openrtb_ext.BidTypeAudio + } + } + } + return openrtb_ext.BidTypeBanner +} diff --git a/adapters/admixer/admixer_test.go b/adapters/admixer/admixer_test.go new file mode 100644 index 00000000000..b379e8b2910 --- /dev/null +++ b/adapters/admixer/admixer_test.go @@ -0,0 +1,10 @@ +package admixer + +import ( + "github.com/prebid/prebid-server/adapters/adapterstest" + "testing" +) + +func TestJsonSamples(t *testing.T) { + adapterstest.RunJSONBidderTest(t, "admixertest", NewAdmixerBidder("http://inv-nets.admixer.net/pbs.aspx")) +} diff --git a/adapters/admixer/admixertest/exemplary/optional-params.json b/adapters/admixer/admixertest/exemplary/optional-params.json new file mode 100644 index 00000000000..9c3fdd11d24 --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/optional-params.json @@ -0,0 +1,47 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "zone": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", + "customFloor": 0.1, + "customParams": {"foo": "bar"} + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "tagid": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", + "bidfloor": 0.1, + "ext": { + "customParams": {"foo": "bar"} + } + } + ] + } + }, + "mockResponse": { + "status": 204 + } + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-app-audio b/adapters/admixer/admixertest/exemplary/simple-app-audio new file mode 100644 index 00000000000..b8c39ead95e --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-app-audio @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"], + "protocols": [9,10] + }, + "ext": { + "bidder": { + "zone": "473e443c-43d0-423d-a8d7-a302637a01d8" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"], + "protocols": [9,10] + }, + "tagid": "473e443c-43d0-423d-a8d7-a302637a01d8" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "admixer", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid" + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid" + }, + "type": "audio" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-app-banner.json b/adapters/admixer/admixertest/exemplary/simple-app-banner.json new file mode 100644 index 00000000000..aff4ccddd64 --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-app-banner.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zone": "2eb6bd58-865c-47ce-af7f-a918108c3fd2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "2eb6bd58-865c-47ce-af7f-a918108c3fd2" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "admixer", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-app-native b/adapters/admixer/admixertest/exemplary/simple-app-native new file mode 100644 index 00000000000..38c005c651c --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-app-native @@ -0,0 +1,90 @@ + +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "ext": { + "bidder": { + "zone": "b1fbebfc-7155-4922-bb86-615e7f3d6eef" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "tagid": "b1fbebfc-7155-4922-bb86-615e7f3d6eef" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "admixer", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid" + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-app-video b/adapters/admixer/admixertest/exemplary/simple-app-video new file mode 100644 index 00000000000..627023fa1e6 --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-app-video @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "zone": "ac7fa772-d7be-48cc-820b-e21728e434fe" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "tagid": "ac7fa772-d7be-48cc-820b-e21728e434fe" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "admixer", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-site-audio.json b/adapters/admixer/admixertest/exemplary/simple-site-audio.json new file mode 100644 index 00000000000..5a1d6531a85 --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-site-audio.json @@ -0,0 +1,89 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"], + "protocols": [9,10] + }, + "ext": { + "bidder": { + "zone": "473e443c-43d0-423d-a8d7-a302637a01d8" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": ["audio/mp4"], + "protocols": [9,10] + }, + "tagid": "473e443c-43d0-423d-a8d7-a302637a01d8" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "admixer", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid" + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid" + }, + "type": "audio" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-site-banner.json b/adapters/admixer/admixertest/exemplary/simple-site-banner.json new file mode 100644 index 00000000000..bd50aba8d1a --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-site-banner.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zone": "2eb6bd58-865c-47ce-af7f-a918108c3fd2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "2eb6bd58-865c-47ce-af7f-a918108c3fd2" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "admixer", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-site-native.json b/adapters/admixer/admixertest/exemplary/simple-site-native.json new file mode 100644 index 00000000000..246d02025b1 --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-site-native.json @@ -0,0 +1,90 @@ + +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "ext": { + "bidder": { + "zone": "b1fbebfc-7155-4922-bb86-615e7f3d6eef" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "ver": "1.1", + "request": "{\"ver\":\"1.0\",\"layout\":1,\"adunit\":1,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":60,\"hmin\":60,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":3,\"required\":0,\"data\":{\"type\":2,\"len\":75}},{\"id\":4,\"required\":0,\"data\":{\"type\":6,\"len\":1000}},{\"id\":5,\"required\":0,\"data\":{\"type\":7,\"len\":1000}},{\"id\":6,\"required\":0,\"data\":{\"type\":11,\"len\":1000}}]}" + }, + "tagid": "b1fbebfc-7155-4922-bb86-615e7f3d6eef" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "admixer", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid" + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid" + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/exemplary/simple-site-video.json b/adapters/admixer/admixertest/exemplary/simple-site-video.json new file mode 100644 index 00000000000..42d771ce86b --- /dev/null +++ b/adapters/admixer/admixertest/exemplary/simple-site-video.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "zone": "ac7fa772-d7be-48cc-820b-e21728e434fe" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "tagid": "ac7fa772-d7be-48cc-820b-e21728e434fe" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "admixer", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/admixer/admixertest/params/race/audio.json b/adapters/admixer/admixertest/params/race/audio.json new file mode 100644 index 00000000000..f9aa771e4b1 --- /dev/null +++ b/adapters/admixer/admixertest/params/race/audio.json @@ -0,0 +1,5 @@ +{ + "zone": "473e443c-43d0-423d-a8d7-a302637a01d8", + "customFloor": 0.1, + "customParams": {"foo": "bar"} +} \ No newline at end of file diff --git a/adapters/admixer/admixertest/params/race/banner.json b/adapters/admixer/admixertest/params/race/banner.json new file mode 100644 index 00000000000..03510f7e1ca --- /dev/null +++ b/adapters/admixer/admixertest/params/race/banner.json @@ -0,0 +1,5 @@ +{ + "zone": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", + "customFloor": 0.1, + "customParams": {"foo": "bar"} +} diff --git a/adapters/admixer/admixertest/params/race/native.json b/adapters/admixer/admixertest/params/race/native.json new file mode 100644 index 00000000000..65712a30228 --- /dev/null +++ b/adapters/admixer/admixertest/params/race/native.json @@ -0,0 +1,5 @@ +{ + "zone": "b1fbebfc-7155-4922-bb86-615e7f3d6eef", + "customFloor": 0.1, + "customParams": {"foo": "bar"} +} \ No newline at end of file diff --git a/adapters/admixer/admixertest/params/race/video.json b/adapters/admixer/admixertest/params/race/video.json new file mode 100644 index 00000000000..5e9bc6e59fd --- /dev/null +++ b/adapters/admixer/admixertest/params/race/video.json @@ -0,0 +1,5 @@ +{ + "zone": "ac7fa772-d7be-48cc-820b-e21728e434fe", + "customFloor": 0.1, + "customParams": {"foo": "bar"} +} diff --git a/adapters/admixer/params_test.go b/adapters/admixer/params_test.go new file mode 100644 index 00000000000..71cccb6a3da --- /dev/null +++ b/adapters/admixer/params_test.go @@ -0,0 +1,57 @@ +package admixer + +import ( + "encoding/json" + "github.com/prebid/prebid-server/openrtb_ext" + "testing" +) + +// This file actually intends to test static/bidder-params/admixer.json +// +// These also validate the format of the external API: request.imp[i].ext.admixer + +// TestValidParams makes sure that the admixer schema accepts all imp.ext fields which we intend to support. +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.BidderAdmixer, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected admixer params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the admixer 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.BidderAdmixer, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"zone": "9FF668A2-4122-462E-AAF8-36EA3A54BA21"}`, + `{"zone": "9ff668a2-4122-462e-aaf8-36ea3a54ba21"}`, + `{"zone": "9FF668A2-4122-462E-AAF8-36EA3A54BA21", "customFloor": 0.1}`, + `{"zone": "9FF668A2-4122-462E-AAF8-36EA3A54BA21", "customParams": {"foo": "bar"}}`, + `{"zone": "9ff668a2-4122-462e-aaf8-36ea3a54ba21", "customFloor": 0.1, "customParams": {"foo": ["bar", "baz"]}}`, +} + +var invalidParams = []string{ + `{"zone": "123"}`, + `{"zone": ""}`, + `{"zone": "ZFF668A2-4122-462E-AAF8-36EA3A54BA21"}`, + `{"zone": "9FF668A2-4122-462E-AAF8-36EA3A54BA211"}`, + `{"zone": "123", "customFloor": "0.1"}`, + `{"zone": "9FF668A2-4122-462E-AAF8-36EA3A54BA21", "customFloor": -0.1}`, + `{"zone": "9FF668A2-4122-462E-AAF8-36EA3A54BA21", "customParams": "foo: bar"}`, +} diff --git a/adapters/admixer/usersync.go b/adapters/admixer/usersync.go new file mode 100644 index 00000000000..0a7f50ab79a --- /dev/null +++ b/adapters/admixer/usersync.go @@ -0,0 +1,11 @@ +package admixer + +import ( + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/usersync" + "text/template" +) + +func NewAdmixerSyncer(temp *template.Template) usersync.Usersyncer { + return adapters.NewSyncer("admixer", 511, temp, adapters.SyncTypeRedirect) +} diff --git a/adapters/admixer/usersync_test.go b/adapters/admixer/usersync_test.go new file mode 100644 index 00000000000..a5715c64a46 --- /dev/null +++ b/adapters/admixer/usersync_test.go @@ -0,0 +1,34 @@ +package admixer + +import ( + "github.com/prebid/prebid-server/privacy" + "github.com/prebid/prebid-server/privacy/ccpa" + "github.com/prebid/prebid-server/privacy/gdpr" + "github.com/stretchr/testify/assert" + "testing" + "text/template" +) + +func TestAdmixerSyncer(t *testing.T) { + syncURL := "https://inv-nets.admixer.net/adxcm.aspx?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir=1&rurl=localhost%2Fsetuid%3Fbidder%3Dadmixer%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%24visitor_cookie%24%24" + syncURLTemplate := template.Must( + template.New("sync-template").Parse(syncURL), + ) + + syncer := NewAdmixerSyncer(syncURLTemplate) + syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{ + GDPR: gdpr.Policy{ + Signal: "A", + Consent: "B", + }, + CCPA: ccpa.Policy{ + Value: "C", + }, + }) + + assert.NoError(t, err) + assert.Equal(t, "https://inv-nets.admixer.net/adxcm.aspx?gdpr=A&gdpr_consent=B&us_privacy=C&redir=1&rurl=localhost%2Fsetuid%3Fbidder%3Dadmixer%26gdpr%3DA%26gdpr_consent%3DB%26uid%3D%24%24visitor_cookie%24%24", syncInfo.URL) + assert.Equal(t, "redirect", syncInfo.Type) + assert.EqualValues(t, 511, syncer.GDPRVendorID()) + assert.Equal(t, false, syncInfo.SupportCORS) +} diff --git a/config/config.go b/config/config.go index 943d18a95de..95eba74db1e 100644 --- a/config/config.go +++ b/config/config.go @@ -491,6 +491,7 @@ func (cfg *Configuration) setDerivedDefaults() { setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdkernelAdn, "https://tag.adkernel.com/syncr?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3DadkernelAdn%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7BUID%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdpone, "https://usersync.adpone.com/csync?redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadpone%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Buid%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdtelligent, "https://sync.adtelligent.com/csync?t=p&ep=0&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadtelligent%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Buid%7D") + setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdmixer, "https://inv-nets.admixer.net/adxcm.aspx?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir=1&rurl="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadmixer%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%24visitor_cookie%24%24") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdvangelists, "https://nep.advangelists.com/xp/user-sync?acctid={aid}&&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadvangelists%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAppnexus, "https://ib.adnxs.com/getuid?"+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadnxs%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D") @@ -673,6 +674,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.adform.endpoint", "http://adx.adform.net/adx") v.SetDefault("adapters.adkernel.endpoint", "http://{{.Host}}/hb?zone={{.ZoneID}}") v.SetDefault("adapters.adkerneladn.endpoint", "http://{{.Host}}/rtbpub?account={{.PublisherID}}") + v.SetDefault("adapters.admixer.endpoint", "http://inv-nets.admixer.net/pbs.aspx") v.SetDefault("adapters.adpone.endpoint", "http://rtb.adpone.com/bid-request?src=prebid_server") v.SetDefault("adapters.adtelligent.endpoint", "http://hb.adtelligent.com/auction") v.SetDefault("adapters.advangelists.endpoint", "http://nep.advangelists.com/xp/get?pubid={{.PublisherID}}") diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go index 95f5b7f5882..1a03464e23f 100644 --- a/exchange/adapter_map.go +++ b/exchange/adapter_map.go @@ -12,6 +12,7 @@ import ( "github.com/prebid/prebid-server/adapters/adform" "github.com/prebid/prebid-server/adapters/adkernel" "github.com/prebid/prebid-server/adapters/adkernelAdn" + "github.com/prebid/prebid-server/adapters/admixer" "github.com/prebid/prebid-server/adapters/adpone" "github.com/prebid/prebid-server/adapters/adtelligent" "github.com/prebid/prebid-server/adapters/advangelists" @@ -71,6 +72,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter openrtb_ext.BidderAdform: adform.NewAdformBidder(client, cfg.Adapters[string(openrtb_ext.BidderAdform)].Endpoint), openrtb_ext.BidderAdkernel: adkernel.NewAdkernelAdapter(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdkernel))].Endpoint), openrtb_ext.BidderAdkernelAdn: adkernelAdn.NewAdkernelAdnAdapter(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdkernelAdn))].Endpoint), + openrtb_ext.BidderAdmixer: admixer.NewAdmixerBidder(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdmixer))].Endpoint), openrtb_ext.BidderAdpone: adpone.NewAdponeBidder(cfg.Adapters[string(openrtb_ext.BidderAdpone)].Endpoint), openrtb_ext.BidderAdtelligent: adtelligent.NewAdtelligentBidder(cfg.Adapters[string(openrtb_ext.BidderAdtelligent)].Endpoint), openrtb_ext.BidderAdvangelists: advangelists.NewAdvangelistsBidder(cfg.Adapters[string(openrtb_ext.BidderAdvangelists)].Endpoint), diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 7a3f24eb07f..8dbfff1e918 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -25,6 +25,7 @@ const ( BidderAdkernel BidderName = "adkernel" BidderAdkernelAdn BidderName = "adkernelAdn" BidderAdpone BidderName = "adpone" + BidderAdmixer BidderName = "admixer" BidderAdtelligent BidderName = "adtelligent" BidderAdvangelists BidderName = "advangelists" BidderApplogy BidderName = "applogy" @@ -79,6 +80,7 @@ var BidderMap = map[string]BidderName{ "adform": BidderAdform, "adkernel": BidderAdkernel, "adkernelAdn": BidderAdkernelAdn, + "admixer": BidderAdmixer, "adpone": BidderAdpone, "adtelligent": BidderAdtelligent, "advangelists": BidderAdvangelists, diff --git a/openrtb_ext/imp_admixer.go b/openrtb_ext/imp_admixer.go new file mode 100644 index 00000000000..ce122ae0029 --- /dev/null +++ b/openrtb_ext/imp_admixer.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ExtImpAdmixer struct { + ZoneId string `json:"zone"` + CustomBidFloor float64 `json:"customFloor"` + CustomParams map[string]interface{} `json:"customParams"` +} diff --git a/static/bidder-info/admixer.yaml b/static/bidder-info/admixer.yaml new file mode 100644 index 00000000000..64ad2024058 --- /dev/null +++ b/static/bidder-info/admixer.yaml @@ -0,0 +1,15 @@ +maintainer: + email: "prebid@admixer.net" +capabilities: + app: + mediaTypes: + - banner + - video + - native + - audio + site: + mediaTypes: + - banner + - video + - native + - audio \ No newline at end of file diff --git a/static/bidder-params/admixer.json b/static/bidder-params/admixer.json new file mode 100644 index 00000000000..886e33ff2bb --- /dev/null +++ b/static/bidder-params/admixer.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Admixer Adapter Params", + "description": "A schema which validates params accepted by the Admixer adapter", + + "type": "object", + "properties": { + "zone": { + "type": "string", + "description": "Zone ID.", + "pattern": "^([a-fA-F\\d\\-]{36})$" + }, + "customFloor": { + "type": "number", + "description": "The minimum CPM price in USD.", + "minimum": 0 + }, + "customParams": { + "type": "object", + "description": "User-defined targeting key-value pairs." + } + }, + + "required": ["zone"] +} diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index 5447cd28800..7aabb1add66 100644 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -1,6 +1,7 @@ package usersyncers import ( + "github.com/prebid/prebid-server/adapters/admixer" "strings" "text/template" @@ -68,6 +69,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync insertIntoMap(cfg, syncers, openrtb_ext.BidderAdform, adform.NewAdformSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderAdkernel, adkernel.NewAdkernelSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderAdkernelAdn, adkernelAdn.NewAdkernelAdnSyncer) + insertIntoMap(cfg, syncers, openrtb_ext.BidderAdmixer, admixer.NewAdmixerSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderAdpone, adpone.NewadponeSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderAdtelligent, adtelligent.NewAdtelligentSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderAdvangelists, advangelists.NewAdvangelistsSyncer) From b35436f7d58ba9903c9bc2cc926d154374b6f604 Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Mon, 17 Feb 2020 16:57:53 +0200 Subject: [PATCH 2/4] admixer-adapter syncer test added --- usersync/usersyncers/syncer_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index ded8fd2bd78..5cd10901894 100644 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -18,6 +18,7 @@ func TestNewSyncerMap(t *testing.T) { string(openrtb_ext.BidderAdform): syncConfig, string(openrtb_ext.BidderAdkernel): syncConfig, string(openrtb_ext.BidderAdkernelAdn): syncConfig, + string(openrtb_ext.BidderAdmixer): syncConfig, string(openrtb_ext.BidderAdpone): syncConfig, string(openrtb_ext.BidderAdtelligent): syncConfig, string(openrtb_ext.BidderAdvangelists): syncConfig, From 9f012aa53448ae2286c2609ba5040aaf2374984f Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Mon, 24 Feb 2020 12:26:04 +0200 Subject: [PATCH 3/4] admixer-adapter tests improved & issues fixed --- adapters/admixer/admixer.go | 47 +++++++++---- .../exemplary/optional-params.json | 69 ++++++++++++++++-- ...simple-app-audio => simple-app-audio.json} | 0 ...mple-app-native => simple-app-native.json} | 0 ...simple-app-video => simple-app-video.json} | 0 .../supplemental/bad-dsp-request-example.json | 70 +++++++++++++++++++ .../dsp-server-internal-error-example.json | 70 +++++++++++++++++++ .../supplemental/ext-unmarshall-error.json | 34 +++++++++ .../unknown-status-code-example.json | 70 +++++++++++++++++++ .../supplemental/wrong-zone-id-error.json | 30 ++++++++ .../supplemental/zero-bid-request-error.json | 19 +++++ usersync/usersyncers/syncer.go | 5 +- 12 files changed, 391 insertions(+), 23 deletions(-) rename adapters/admixer/admixertest/exemplary/{simple-app-audio => simple-app-audio.json} (100%) rename adapters/admixer/admixertest/exemplary/{simple-app-native => simple-app-native.json} (100%) rename adapters/admixer/admixertest/exemplary/{simple-app-video => simple-app-video.json} (100%) create mode 100644 adapters/admixer/admixertest/supplemental/bad-dsp-request-example.json create mode 100644 adapters/admixer/admixertest/supplemental/dsp-server-internal-error-example.json create mode 100644 adapters/admixer/admixertest/supplemental/ext-unmarshall-error.json create mode 100644 adapters/admixer/admixertest/supplemental/unknown-status-code-example.json create mode 100644 adapters/admixer/admixertest/supplemental/wrong-zone-id-error.json create mode 100644 adapters/admixer/admixertest/supplemental/zero-bid-request-error.json diff --git a/adapters/admixer/admixer.go b/adapters/admixer/admixer.go index 7257014dd21..65a94f352ed 100644 --- a/adapters/admixer/admixer.go +++ b/adapters/admixer/admixer.go @@ -24,11 +24,13 @@ type admixerImpExt struct { func (a *AdmixerAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) (requests []*adapters.RequestData, errors []error) { rq, errs := a.makeRequest(request) + if len(errs) > 0 { errors = append(errors, errs...) return } - if request != nil { + + if rq != nil { requests = append(requests, rq) } @@ -39,6 +41,12 @@ func (a *AdmixerAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.Req var errs []error var validImps []openrtb.Imp + if len(request.Imp) == 0 { + return nil, []error{&errortypes.BadInput{ + Message: "No impressions in request", + }} + } + for _, imp := range request.Imp { if err := preprocess(&imp); err != nil { errs = append(errs, err) @@ -81,7 +89,14 @@ func preprocess(imp *openrtb.Imp) error { var admixerExt openrtb_ext.ExtImpAdmixer if err := json.Unmarshal(bidderExt.Bidder, &admixerExt); err != nil { return &errortypes.BadInput{ - Message: err.Error(), + Message: "Wrong Admixer bidder ext", + } + } + + //don't use regexp due to possible performance reduce + if len(admixerExt.ZoneId) != 36 { + return &errortypes.BadInput{ + Message: "ZoneId must be UUID/GUID", } } @@ -91,15 +106,13 @@ func preprocess(imp *openrtb.Imp) error { imp.Ext = nil if admixerExt.CustomParams != nil { - if admixerExt.CustomParams != nil { - impExt := admixerImpExt{ - CustomParams: admixerExt.CustomParams, - } - var err error - if imp.Ext, err = json.Marshal(impExt); err != nil { - return &errortypes.BadInput{ - Message: err.Error(), - } + impExt := admixerImpExt{ + CustomParams: admixerExt.CustomParams, + } + var err error + if imp.Ext, err = json.Marshal(impExt); err != nil { + return &errortypes.BadInput{ + Message: err.Error(), } } } @@ -112,15 +125,21 @@ func (a *AdmixerAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalR return nil, nil } - if response.StatusCode == http.StatusBadRequest { + if response.StatusCode >= http.StatusInternalServerError { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Dsp server internal error", response.StatusCode), + }} + } + + if response.StatusCode >= http.StatusBadRequest { return nil, []error{&errortypes.BadInput{ - Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + Message: fmt.Sprintf("Unexpected status code: %d. Bad request to dsp", response.StatusCode), }} } if response.StatusCode != http.StatusOK { return nil, []error{&errortypes.BadServerResponse{ - Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + Message: fmt.Sprintf("Unexpected status code: %d", response.StatusCode), }} } diff --git a/adapters/admixer/admixertest/exemplary/optional-params.json b/adapters/admixer/admixertest/exemplary/optional-params.json index 9c3fdd11d24..42a55ec95e8 100644 --- a/adapters/admixer/admixertest/exemplary/optional-params.json +++ b/adapters/admixer/admixertest/exemplary/optional-params.json @@ -5,19 +5,48 @@ { "id": "test-imp-id", "banner": { - "format": [{"w": 728, "h": 90}] + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zone": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", + "customFloor": 0.1, + "customParams": { + "foo": "bar" + } + } + } + }, + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "ext": { "bidder": { "zone": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", "customFloor": 0.1, - "customParams": {"foo": "bar"} + "customParams": { + "foo": [ + "bar", + "baz" + ] + } } } } ] }, - "httpCalls": [ { "expectedRequest": { @@ -26,14 +55,42 @@ "id": "test-request-id", "imp": [ { - "id":"test-imp-id", + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", + "bidfloor": 0.1, + "ext": { + "customParams": { + "foo": "bar" + } + } + }, + { + "id": "test-imp-id", "banner": { - "format": [{"w": 728, "h": 90}] + "format": [ + { + "w": 728, + "h": 90 + } + ] }, "tagid": "2eb6bd58-865c-47ce-af7f-a918108c3fd2", "bidfloor": 0.1, "ext": { - "customParams": {"foo": "bar"} + "customParams": { + "foo": [ + "bar", + "baz" + ] + } } } ] diff --git a/adapters/admixer/admixertest/exemplary/simple-app-audio b/adapters/admixer/admixertest/exemplary/simple-app-audio.json similarity index 100% rename from adapters/admixer/admixertest/exemplary/simple-app-audio rename to adapters/admixer/admixertest/exemplary/simple-app-audio.json diff --git a/adapters/admixer/admixertest/exemplary/simple-app-native b/adapters/admixer/admixertest/exemplary/simple-app-native.json similarity index 100% rename from adapters/admixer/admixertest/exemplary/simple-app-native rename to adapters/admixer/admixertest/exemplary/simple-app-native.json diff --git a/adapters/admixer/admixertest/exemplary/simple-app-video b/adapters/admixer/admixertest/exemplary/simple-app-video.json similarity index 100% rename from adapters/admixer/admixertest/exemplary/simple-app-video rename to adapters/admixer/admixertest/exemplary/simple-app-video.json diff --git a/adapters/admixer/admixertest/supplemental/bad-dsp-request-example.json b/adapters/admixer/admixertest/supplemental/bad-dsp-request-example.json new file mode 100644 index 00000000000..5256c14050b --- /dev/null +++ b/adapters/admixer/admixertest/supplemental/bad-dsp-request-example.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zone": "3e56bd58-865c-47ce-af7f-a918108c3fd2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "3e56bd58-865c-47ce-af7f-a918108c3fd2" + } + ] + } + }, + "mockResponse": { + "status": 400, + "body": { + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Bad request to dsp", + "comparison": "literal" + } + ] +} diff --git a/adapters/admixer/admixertest/supplemental/dsp-server-internal-error-example.json b/adapters/admixer/admixertest/supplemental/dsp-server-internal-error-example.json new file mode 100644 index 00000000000..1c06eadce44 --- /dev/null +++ b/adapters/admixer/admixertest/supplemental/dsp-server-internal-error-example.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zone": "3e56bd58-865c-47ce-af7f-a918108c3fd2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "3e56bd58-865c-47ce-af7f-a918108c3fd2" + } + ] + } + }, + "mockResponse": { + "status": 500, + "body": { + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Dsp server internal error", + "comparison": "literal" + } + ] +} diff --git a/adapters/admixer/admixertest/supplemental/ext-unmarshall-error.json b/adapters/admixer/admixertest/supplemental/ext-unmarshall-error.json new file mode 100644 index 00000000000..e14a26356f8 --- /dev/null +++ b/adapters/admixer/admixertest/supplemental/ext-unmarshall-error.json @@ -0,0 +1,34 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "format": [ + { + "w": 728, + "h": 90 + } + ], + "ext": { + "bidder": { + "zone": [ + "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + ] + } + } + } + ], + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Wrong Admixer bidder ext", + "comparison": "literal" + } + ] +} diff --git a/adapters/admixer/admixertest/supplemental/unknown-status-code-example.json b/adapters/admixer/admixertest/supplemental/unknown-status-code-example.json new file mode 100644 index 00000000000..972f2f5dd01 --- /dev/null +++ b/adapters/admixer/admixertest/supplemental/unknown-status-code-example.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zone": "3e56bd58-865c-47ce-af7f-a918108c3fd2" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://inv-nets.admixer.net/pbs.aspx", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "3e56bd58-865c-47ce-af7f-a918108c3fd2" + } + ] + } + }, + "mockResponse": { + "status": 301, + "body": { + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 301", + "comparison": "literal" + } + ] +} diff --git a/adapters/admixer/admixertest/supplemental/wrong-zone-id-error.json b/adapters/admixer/admixertest/supplemental/wrong-zone-id-error.json new file mode 100644 index 00000000000..2f2dcec1a50 --- /dev/null +++ b/adapters/admixer/admixertest/supplemental/wrong-zone-id-error.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "format": [{ + "w": 728, + "h": 90 + }], + "ext": { + "bidder": { + "zone": "12345" + } + } + } + ], + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "ZoneId must be UUID/GUID", + "comparison": "literal" + } + ] +} diff --git a/adapters/admixer/admixertest/supplemental/zero-bid-request-error.json b/adapters/admixer/admixertest/supplemental/zero-bid-request-error.json new file mode 100644 index 00000000000..a43d9b5fa65 --- /dev/null +++ b/adapters/admixer/admixertest/supplemental/zero-bid-request-error.json @@ -0,0 +1,19 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + ], + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa":"ec943cb9-61ec-460f-a925-6489c3fcc4e3" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "No impressions in request", + "comparison": "literal" + } + ] +} diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index 7aabb1add66..7f65c7f476f 100644 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -1,17 +1,16 @@ package usersyncers import ( - "github.com/prebid/prebid-server/adapters/admixer" "strings" "text/template" - "github.com/prebid/prebid-server/adapters/adpone" - "github.com/golang/glog" ttx "github.com/prebid/prebid-server/adapters/33across" "github.com/prebid/prebid-server/adapters/adform" "github.com/prebid/prebid-server/adapters/adkernel" "github.com/prebid/prebid-server/adapters/adkernelAdn" + "github.com/prebid/prebid-server/adapters/admixer" + "github.com/prebid/prebid-server/adapters/adpone" "github.com/prebid/prebid-server/adapters/adtelligent" "github.com/prebid/prebid-server/adapters/advangelists" "github.com/prebid/prebid-server/adapters/appnexus" From adc2b2b4af2766011e559e9b9258c1b1418787aa Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Mon, 24 Feb 2020 16:30:40 +0200 Subject: [PATCH 4/4] Merge remote-tracking branch 'origin/master' into admixer-adapter --- exchange/adapter_map.go | 2 ++ go.mod | 15 +++++++++-- go.sum | 60 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go index d20fa65a17f..4c6da00f337 100644 --- a/exchange/adapter_map.go +++ b/exchange/adapter_map.go @@ -73,6 +73,8 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter openrtb_ext.BidderAdform: adform.NewAdformBidder(client, cfg.Adapters[string(openrtb_ext.BidderAdform)].Endpoint), openrtb_ext.BidderAdkernel: adkernel.NewAdkernelAdapter(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdkernel))].Endpoint), openrtb_ext.BidderAdkernelAdn: adkernelAdn.NewAdkernelAdnAdapter(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdkernelAdn))].Endpoint), + openrtb_ext.BidderAdmixer: admixer.NewAdmixerBidder(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdmixer))].Endpoint), + openrtb_ext.BidderAdoppler: adoppler.NewAdopplerBidder(cfg.Adapters[string(openrtb_ext.BidderAdoppler)].Endpoint), openrtb_ext.BidderAdpone: adpone.NewAdponeBidder(cfg.Adapters[string(openrtb_ext.BidderAdpone)].Endpoint), openrtb_ext.BidderAdtelligent: adtelligent.NewAdtelligentBidder(cfg.Adapters[string(openrtb_ext.BidderAdtelligent)].Endpoint), openrtb_ext.BidderAdvangelists: advangelists.NewAdvangelistsBidder(cfg.Adapters[string(openrtb_ext.BidderAdvangelists)].Endpoint), diff --git a/go.mod b/go.mod index 5c837c2ee7b..af4bf5570a5 100644 --- a/go.mod +++ b/go.mod @@ -7,17 +7,23 @@ require ( github.com/DATA-DOG/go-sqlmock v1.3.0 github.com/NYTimes/gziphandler v1.1.1 github.com/OneOfOne/xxhash v1.2.5 // indirect + github.com/aerospike/aerospike-client-go v2.7.2+incompatible github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect github.com/blang/semver v3.5.1+incompatible + github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44 github.com/cespare/xxhash v1.0.0 // indirect github.com/chasex/glog v0.0.0-20160217080310-c62392af379c github.com/coocood/freecache v1.0.1 + github.com/didip/tollbooth v4.0.2+incompatible github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 github.com/evanphx/json-patch v0.0.0-20180720181644-f195058310bd + github.com/go-redis/redis v6.15.7+incompatible + github.com/gocql/gocql v0.0.0-20200203083758-81b8263d9fe5 github.com/gofrs/uuid v3.2.0+incompatible github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + github.com/golang/snappy v0.0.1 github.com/hashicorp/hcl v1.0.0 // indirect github.com/influxdata/influxdb v1.6.1 // indirect github.com/julienschmidt/httprouter v1.1.0 @@ -31,8 +37,10 @@ require ( github.com/mxmCherry/openrtb v11.0.0+incompatible github.com/onsi/ginkgo v1.10.1 // indirect github.com/onsi/gomega v1.7.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.2.0 // indirect github.com/prebid/go-gdpr v0.6.0 + github.com/prebid/prebid-cache v0.0.0-20200218152159-6d6d678c1caf github.com/prometheus/client_golang v0.0.0-20180623155954-77e8f2ddcfed github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect @@ -40,14 +48,15 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 github.com/rs/cors v1.5.0 github.com/sergi/go-diff v1.0.0 // indirect + github.com/sirupsen/logrus v1.4.2 github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.1.1 // indirect github.com/spf13/cast v1.2.0 // indirect github.com/spf13/jwalterweatherman v0.0.0-20180814060501-14d3d4c51834 // indirect github.com/spf13/pflag v1.0.2 // indirect github.com/spf13/viper v1.1.0 - github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/testify v1.3.0 + github.com/valyala/fasthttp v1.9.0 github.com/vrischmann/go-metrics-influxdb v0.0.0-20160917065939-43af8332c303 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -55,8 +64,10 @@ require ( github.com/yudai/gojsondiff v0.0.0-20170107030110-7b1b7adf999d github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yudai/pp v2.0.1+incompatible // indirect - golang.org/x/net v0.0.0-20180906233101-161cd47e91fd + github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect + golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect golang.org/x/text v0.3.0 + golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect gopkg.in/yaml.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index 57fcbb76428..06f07b1ece0 100644 --- a/go.sum +++ b/go.sum @@ -6,35 +6,57 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/aerospike/aerospike-client-go v2.7.2+incompatible h1:bWbRf8trg1FhKF7u43KLGNfOH60RlvIgQjpaS107DZ8= +github.com/aerospike/aerospike-client-go v2.7.2+incompatible/go.mod h1:zj8LBEnWBDOVEIJt8LvaRvDG5ARAoa5dBeHaB472NRc= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44 h1:y853v6rXx+zefEcjET3JuKAqvhj+FKflQijjeaSv2iA= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cespare/xxhash v1.0.0 h1:naDmySfoNg0nKS62/ujM6e71ZgM2AoVdaqGwMG0w18A= github.com/cespare/xxhash v1.0.0/go.mod h1:fX/lfQBkSCDXZSUgv6jVIu/EVA3/JNseAX5asI4c4T4= github.com/chasex/glog v0.0.0-20160217080310-c62392af379c h1:eXqCBUHfmjbeDqcuvzjsd+bM6A+bnwo5N9FVbV6m5/s= github.com/chasex/glog v0.0.0-20160217080310-c62392af379c/go.mod h1:omJZNg0Qu76bxJd+ExohVo8uXzNcGOk2bv7vel460xk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coocood/freecache v1.0.1 h1:oFyo4msX2c0QIKU+kuMJUwsKamJ+AKc2JJrKcMszJ5M= github.com/coocood/freecache v1.0.1/go.mod h1:ePwxCDzOYvARfHdr1pByNct1at3CoKnsipOHwKlNbzI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/didip/tollbooth v4.0.2+incompatible h1:fVSa33JzSz0hoh2NxpwZtksAzAgd7zjmGO20HCZtF4M= +github.com/didip/tollbooth v4.0.2+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/evanphx/json-patch v0.0.0-20180720181644-f195058310bd h1:biTJQdqouE5by89AAffXG8++TY+9Fsdrg5rinbt3tHk= github.com/evanphx/json-patch v0.0.0-20180720181644-f195058310bd/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U= +github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/gocql/gocql v0.0.0-20200203083758-81b8263d9fe5 h1:ZZVxQRCm4ewuoqqLBJ7LHpsk4OGx2PkyCsRKLq4oHgE= +github.com/gocql/gocql v0.0.0-20200203083758-81b8263d9fe5/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -45,6 +67,17 @@ github.com/julienschmidt/httprouter v1.1.0 h1:7wLdtIiIpzOkC9u6sXOozpBauPdskj3ru4 github.com/julienschmidt/httprouter v1.1.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= @@ -66,18 +99,20 @@ github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prebid/go-gdpr v0.6.0 h1:/GKrygGkUbsgd96HIkjAu7/6CHtRedvcojRtfAd4Igc= github.com/prebid/go-gdpr v0.6.0/go.mod h1:FPY0uxSrl9/Mz237LnPo3ge4aCG0wQ9FWf2b4WhwNn0= +github.com/prebid/prebid-cache v0.0.0-20200218152159-6d6d678c1caf h1:CcE+KN1tCtWKsUFH5IzdQxHIgP609VSIVe5Hywg2phs= +github.com/prebid/prebid-cache v0.0.0-20200218152159-6d6d678c1caf/go.mod h1:k5xrl5ZpnumN1S2x8w8cMiFYsgRuVyAeFJz+BkSi+98= github.com/prometheus/client_golang v0.0.0-20180623155954-77e8f2ddcfed h1:0dloFFFNNDG7c+8qtkYw2FdADrWy9s5cI8wHp6tK3Mg= github.com/prometheus/client_golang v0.0.0-20180623155954-77e8f2ddcfed/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0= @@ -88,6 +123,8 @@ github.com/rs/cors v1.5.0 h1:dgSHE6+ia18arGOTIYQKKGWLvEbGvmbNE6NfxhoNHUY= github.com/rs/cors v1.5.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I= @@ -103,8 +140,14 @@ github.com/spf13/viper v1.1.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7Sr github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.9.0 h1:hNpmUdy/+ZXYpGy0OBfm7K0UQTzb73W0T0U4iJIVrMw= +github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vrischmann/go-metrics-influxdb v0.0.0-20160917065939-43af8332c303 h1:Va10CytCCYRm4xBTses5ZDeDjeIQjhaiC9nRCe/yflI= github.com/vrischmann/go-metrics-influxdb v0.0.0-20160917065939-43af8332c303/go.mod h1:Xdcad1nGVhQfhoV0go+/4WaI/RZkWlvfjkVCdpMTxPY= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -119,21 +162,34 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= +github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=