Skip to content
This repository has been archived by the owner on Dec 22, 2022. It is now read-only.

Commit

Permalink
[Sharethrough] Implement Cookie Sync + misc improvements (prebid#1016)
Browse files Browse the repository at this point in the history
* Add cookie sync support with buyer id (prebid#22)

* Add cookie sync support with buyer id

[#167607401]

* Rename STX user id butler param

[#167607401]

From stx_user_id to stxuid (https://www.pivotaltracker.com/n/projects/1031568/stories/167658270)

* Set finalized cookie sync URL

[#167607401]

* Switch cookie sync URL to HTTPS

[#167607401]

* Fix GDPR flag

[#167607401]

* Refactor the way the ad payload is passed to the ad markup (prebid#23)

[#166100996]

* Add test for NewSharethroughBidder
  • Loading branch information
Mathieu Pheulpin authored and hhhjort committed Sep 5, 2019
1 parent e07be1a commit 8759b67
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 143 deletions.
20 changes: 15 additions & 5 deletions adapters/sharethrough/butler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ type StrAdSeverParams struct {
Height uint64
Width uint64
TheTradeDeskUserId string
SharethroughUserId string
}

type StrOpenRTBInterface interface {
requestFromOpenRTB(openrtb.Imp, *openrtb.BidRequest, string) (*adapters.RequestData, error)
responseToOpenRTB(openrtb_ext.ExtImpSharethroughResponse, *adapters.RequestData) (*adapters.BidderResponse, []error)
responseToOpenRTB([]byte, *adapters.RequestData) (*adapters.BidderResponse, []error)
}

type StrAdServerUriInterface interface {
Expand Down Expand Up @@ -64,7 +65,7 @@ func (s StrOpenRTBTranslator) requestFromOpenRTB(imp openrtb.Imp, request *openr
if err := json.Unmarshal(imp.Ext, &strImpExt); err != nil {
return nil, err
}
var strImpParams openrtb_ext.ExtImpSharethroughExt
var strImpParams openrtb_ext.ExtImpSharethrough
if err := json.Unmarshal(strImpExt.Bidder, &strImpParams); err != nil {
return nil, err
}
Expand All @@ -91,14 +92,20 @@ func (s StrOpenRTBTranslator) requestFromOpenRTB(imp openrtb.Imp, request *openr
Width: width,
InstantPlayCapable: s.Util.canAutoPlayVideo(request.Device.UA, s.UserAgentParsers),
TheTradeDeskUserId: userInfo.TtdUid,
SharethroughUserId: request.User.BuyerUID,
}),
Body: nil,
Headers: headers,
}, nil
}

func (s StrOpenRTBTranslator) responseToOpenRTB(strResp openrtb_ext.ExtImpSharethroughResponse, btlrReq *adapters.RequestData) (*adapters.BidderResponse, []error) {
func (s StrOpenRTBTranslator) responseToOpenRTB(strRawResp []byte, btlrReq *adapters.RequestData) (*adapters.BidderResponse, []error) {
var errs []error

var strResp openrtb_ext.ExtImpSharethroughResponse
if err := json.Unmarshal(strRawResp, &strResp); err != nil {
return nil, []error{&errortypes.BadInput{Message: "Unable to parse response JSON"}}
}
bidResponse := adapters.NewBidderResponse()

bidResponse.Currency = "USD"
Expand All @@ -116,7 +123,7 @@ func (s StrOpenRTBTranslator) responseToOpenRTB(strResp openrtb_ext.ExtImpSharet
return nil, errs
}

adm, admErr := s.Util.getAdMarkup(strResp, btlrParams)
adm, admErr := s.Util.getAdMarkup(strRawResp, strResp, btlrParams)
if admErr != nil {
errs = append(errs, &errortypes.BadServerResponse{Message: admErr.Error()})
return nil, errs
Expand Down Expand Up @@ -150,14 +157,17 @@ func (h StrUriHelper) buildUri(params StrAdSeverParams) string {
if params.TheTradeDeskUserId != "" {
v.Set("ttduid", params.TheTradeDeskUserId)
}
if params.SharethroughUserId != "" {
v.Set("stxuid", params.SharethroughUserId)
}

v.Set("instant_play_capable", fmt.Sprintf("%t", params.InstantPlayCapable))
v.Set("stayInIframe", fmt.Sprintf("%t", params.Iframe))
v.Set("height", strconv.FormatUint(params.Height, 10))
v.Set("width", strconv.FormatUint(params.Width, 10))

v.Set("supplyId", supplyId)
v.Set("strVersion", strVersion)
v.Set("strVersion", strconv.FormatInt(strVersion, 10))

return h.BaseURI + "?" + v.Encode()
}
Expand Down
41 changes: 19 additions & 22 deletions adapters/sharethrough/butler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/prebid/prebid-server/openrtb_ext"
"net/http"
"regexp"
"strconv"
"strings"
"testing"
)
Expand Down Expand Up @@ -84,6 +85,7 @@ func TestSuccessRequestFromOpenRTB(t *testing.T) {
IP: "127.0.0.1",
},
Site: &openrtb.Site{Page: "http://a.domain.com/page"},
User: &openrtb.User{},
},
inputDom: "http://a.domain.com",
expected: &adapters.RequestData{
Expand Down Expand Up @@ -165,26 +167,15 @@ func assertBidderResponseEquals(t *testing.T, testName string, expected adapters
func TestSuccessResponseToOpenRTB(t *testing.T) {
tests := map[string]struct {
inputButlerReq *adapters.RequestData
inputStrResp openrtb_ext.ExtImpSharethroughResponse
inputStrResp []byte
expectedSuccess *adapters.BidderResponse
expectedErrors []error
}{
"Generates expected openRTB bid response": {
inputButlerReq: &adapters.RequestData{
Uri: "http://uri.com?placement_key=pkey&bidId=bidid&height=20&width=30",
},
inputStrResp: openrtb_ext.ExtImpSharethroughResponse{
AdServerRequestID: "arid",
BidID: "bid",
Creatives: []openrtb_ext.ExtImpSharethroughCreative{{
CPM: 10,
Metadata: openrtb_ext.ExtImpSharethroughCreativeMetadata{
CampaignKey: "cmpKey",
CreativeKey: "creaKey",
DealID: "dealId",
},
}},
},
inputStrResp: []byte(`{ "adserverRequestId": "arid", "bidId": "bid", "creatives": [{"cpm": 10, "creative": {"campaign_key": "cmpKey", "creative_key": "creaKey", "deal_id": "dealId"}}] }`),
expectedSuccess: &adapters.BidderResponse{
Bids: []*adapters.TypedBid{{
BidType: openrtb_ext.BidTypeNative,
Expand Down Expand Up @@ -218,15 +209,13 @@ func TestSuccessResponseToOpenRTB(t *testing.T) {
func TestFailResponseToOpenRTB(t *testing.T) {
tests := map[string]struct {
inputButlerReq *adapters.RequestData
inputStrResp openrtb_ext.ExtImpSharethroughResponse
inputStrResp []byte
expectedSuccess *adapters.BidderResponse
expectedErrors []error
}{
"Returns nil if no creatives provided": {
inputButlerReq: &adapters.RequestData{},
inputStrResp: openrtb_ext.ExtImpSharethroughResponse{
Creatives: []openrtb_ext.ExtImpSharethroughCreative{},
},
inputButlerReq: &adapters.RequestData{},
inputStrResp: []byte(`{}`),
expectedSuccess: nil,
expectedErrors: []error{
&errortypes.BadInput{Message: "No creative provided"},
Expand All @@ -236,14 +225,20 @@ func TestFailResponseToOpenRTB(t *testing.T) {
inputButlerReq: &adapters.RequestData{
Uri: "wrong format url",
},
inputStrResp: openrtb_ext.ExtImpSharethroughResponse{
Creatives: []openrtb_ext.ExtImpSharethroughCreative{{}},
},
inputStrResp: []byte(`{ "creatives": [{"creative": {}}] }`),
expectedSuccess: nil,
expectedErrors: []error{
&errortypes.BadInput{Message: `strconv.ParseUint: parsing "": invalid syntax`},
},
},
"Returns error if failed parsing body": {
inputButlerReq: &adapters.RequestData{},
inputStrResp: []byte(`{ wrong json`),
expectedSuccess: nil,
expectedErrors: []error{
&errortypes.BadInput{Message: "Unable to parse response JSON"},
},
},
}

adServer := StrOpenRTBTranslator{UriHelper: StrUriHelper{}}
Expand Down Expand Up @@ -287,6 +282,7 @@ func TestBuildUri(t *testing.T) {
Height: 20,
Width: 30,
TheTradeDeskUserId: "ttd123",
SharethroughUserId: "stx123",
},
expected: []string{
"http://abc.com?",
Expand All @@ -299,8 +295,9 @@ func TestBuildUri(t *testing.T) {
"height=20",
"width=30",
"supplyId=FGMrCMMc",
"strVersion=" + strVersion,
"strVersion=" + strconv.FormatInt(strVersion, 10),
"ttduid=ttd123",
"stxuid=stx123",
},
},
}
Expand Down
11 changes: 2 additions & 9 deletions adapters/sharethrough/sharethrough.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package sharethrough

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"
"regexp"
)

const supplyId = "FGMrCMMc"
const strVersion = "1.0.3"
const strVersion = 4

func NewSharethroughBidder(endpoint string) *SharethroughAdapter {
return &SharethroughAdapter{
Expand Down Expand Up @@ -68,10 +66,5 @@ func (a SharethroughAdapter) MakeBids(internalRequest *openrtb.BidRequest, exter
return nil, []error{fmt.Errorf("unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)}
}

var strBidResp openrtb_ext.ExtImpSharethroughResponse
if err := json.Unmarshal(response.Body, &strBidResp); err != nil {
return nil, []error{err}
}

return a.AdServer.responseToOpenRTB(strBidResp, externalRequest)
return a.AdServer.responseToOpenRTB(response.Body, externalRequest)
}
42 changes: 33 additions & 9 deletions adapters/sharethrough/sharethrough_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/openrtb_ext"
"github.com/stretchr/testify/assert"
"net/http"
"regexp"
"testing"
)

Expand All @@ -21,7 +22,7 @@ func (m MockStrAdServer) requestFromOpenRTB(imp openrtb.Imp, request *openrtb.Bi
return m.mockRequestFromOpenRTB()
}

func (m MockStrAdServer) responseToOpenRTB(strResp openrtb_ext.ExtImpSharethroughResponse, btlrReq *adapters.RequestData) (*adapters.BidderResponse, []error) {
func (m MockStrAdServer) responseToOpenRTB(strRawResp []byte, btlrReq *adapters.RequestData) (*adapters.BidderResponse, []error) {
return m.mockResponseToOpenRTB()
}

Expand All @@ -40,6 +41,36 @@ func (m MockStrUriHelper) parseUri(uri string) (*StrAdSeverParams, error) {
return m.mockParseUri()
}

func TestNewSharethroughBidder(t *testing.T) {
tests := map[string]struct {
input string
output SharethroughAdapter
}{
"Creates Sharethrough adapter": {
input: "test endpoint",
output: SharethroughAdapter{
AdServer: StrOpenRTBTranslator{
UriHelper: StrUriHelper{BaseURI: "test endpoint"},
Util: Util{},
UserAgentParsers: UserAgentParsers{
ChromeVersion: regexp.MustCompile(`Chrome\/(?P<ChromeVersion>\d+)`),
ChromeiOSVersion: regexp.MustCompile(`CriOS\/(?P<chromeiOSVersion>\d+)`),
SafariVersion: regexp.MustCompile(`Version\/(?P<safariVersion>\d+)`),
},
},
},
},
}

assert := assert.New(t)
for testName, test := range tests {
t.Logf("Test case: %s\n", testName)

actual := NewSharethroughBidder(test.input)
assert.Equal(actual, &test.output)
}
}

func TestSuccessMakeRequests(t *testing.T) {
stubReq := &adapters.RequestData{
Method: "POST",
Expand Down Expand Up @@ -209,13 +240,6 @@ func TestFailureMakeBids(t *testing.T) {
},
expected: []error{fmt.Errorf("unexpected status code: %d. Run with request.debug = 1 for more info", http.StatusInternalServerError)},
},
"Returns error if failed parsing body": {
inputResponse: &adapters.ResponseData{
StatusCode: http.StatusOK,
Body: []byte(`{ wrong json`),
},
expected: []error{fmt.Errorf("invalid character 'w' looking for beginning of object key string")},
},
"Passes by errors from responseToOpenRTB": {
inputResponse: &adapters.ResponseData{
StatusCode: http.StatusOK,
Expand Down
10 changes: 3 additions & 7 deletions adapters/sharethrough/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type UtilityInterface interface {
gdprApplies(*openrtb.BidRequest) bool
parseUserExt(*openrtb.User) userInfo

getAdMarkup(openrtb_ext.ExtImpSharethroughResponse, *StrAdSeverParams) (string, error)
getAdMarkup([]byte, openrtb_ext.ExtImpSharethroughResponse, *StrAdSeverParams) (string, error)
getPlacementSize([]openrtb.Format) (uint64, uint64)

canAutoPlayVideo(string, UserAgentParsers) bool
Expand All @@ -46,12 +46,8 @@ type userInfo struct {
TtdUid string
}

func (u Util) getAdMarkup(strResp openrtb_ext.ExtImpSharethroughResponse, params *StrAdSeverParams) (string, error) {
func (u Util) getAdMarkup(strRawResp []byte, strResp openrtb_ext.ExtImpSharethroughResponse, params *StrAdSeverParams) (string, error) {
strRespId := fmt.Sprintf("str_response_%s", strResp.BidID)
jsonPayload, err := json.Marshal(strResp)
if err != nil {
return "", err
}

tmplBody := `
<img src="//b.sharethrough.com/butler?type=s2s-win&arid={{.Arid}}" />
Expand Down Expand Up @@ -93,7 +89,7 @@ func (u Util) getAdMarkup(strResp openrtb_ext.ExtImpSharethroughResponse, params
var buf []byte
templatedBuf := bytes.NewBuffer(buf)

b64EncodedJson := base64.StdEncoding.EncodeToString(jsonPayload)
b64EncodedJson := base64.StdEncoding.EncodeToString(strRawResp)
err = tmpl.Execute(templatedBuf, struct {
Arid template.JS
Pkey string
Expand Down
20 changes: 13 additions & 7 deletions adapters/sharethrough/utils_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package sharethrough

import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/openrtb_ext"
"github.com/stretchr/testify/assert"
Expand All @@ -10,39 +13,39 @@ import (

func TestGetAdMarkup(t *testing.T) {
tests := map[string]struct {
inputResponse openrtb_ext.ExtImpSharethroughResponse
inputResponse []byte
inputParams *StrAdSeverParams
expectedSuccess []string
expectedError error
}{
"Sets template variables": {
inputResponse: openrtb_ext.ExtImpSharethroughResponse{BidID: "bid", AdServerRequestID: "arid"},
inputResponse: []byte(`{"bidId": "bid", "adserverRequestId": "arid"}`),
inputParams: &StrAdSeverParams{Pkey: "pkey"},
expectedSuccess: []string{
`<img src="//b.sharethrough.com/butler?type=s2s-win&arid=arid" />`,
`<div data-str-native-key="pkey" data-stx-response-name="str_response_bid"></div>`,
`<script>var str_response_bid = "eyJhZHNlcnZlclJlcXVlc3RJZCI6ImFyaWQiLCJiaWRJZCI6ImJpZCIsImNvb2tpZVN5bmNVcmxzIjpudWxsLCJjcmVhdGl2ZXMiOm51bGwsInBsYWNlbWVudCI6eyJhbGxvd19pbnN0YW50X3BsYXkiOmZhbHNlLCJhcnRpY2xlc19iZWZvcmVfZmlyc3RfYWQiOjAsImFydGljbGVzX2JldHdlZW5fYWRzIjowLCJsYXlvdXQiOiIiLCJtZXRhZGF0YSI6bnVsbCwicGxhY2VtZW50QXR0cmlidXRlcyI6eyJhZF9zZXJ2ZXJfa2V5IjoiIiwiYWRfc2VydmVyX3BhdGgiOiIiLCJhbGxvd19keW5hbWljX2Nyb3BwaW5nIjpmYWxzZSwiYXBwX3RoaXJkX3BhcnR5X3BhcnRuZXJzIjpudWxsLCJjdXN0b21fY2FyZF9jc3MiOiIiLCJkZnBfcGF0aCI6IiIsImRpcmVjdF9zZWxsX3Byb21vdGVkX2J5X3RleHQiOiIiLCJkb21haW4iOiIiLCJlbmFibGVfbGlua19yZWRpcmVjdGlvbiI6ZmFsc2UsImZlYXR1cmVkX2NvbnRlbnQiOm51bGwsIm1heF9oZWFkbGluZV9sZW5ndGgiOjAsIm11bHRpX2FkX3BsYWNlbWVudCI6ZmFsc2UsInByb21vdGVkX2J5X3RleHQiOiIiLCJwdWJsaXNoZXJfa2V5IjoiIiwicmVuZGVyaW5nX3BpeGVsX29mZnNldCI6MCwic2FmZV9mcmFtZV9zaXplIjpudWxsLCJzaXRlX2tleSI6IiIsInN0cl9vcHRfb3V0X3VybCI6IiIsInRlbXBsYXRlIjoiIiwidGhpcmRfcGFydHlfcGFydG5lcnMiOm51bGx9LCJzdGF0dXMiOiIifSwic3R4VXNlcklkIjoiIn0="</script>`,
fmt.Sprintf(`<script>var str_response_bid = "%s"</script>`, base64.StdEncoding.EncodeToString([]byte(`{"bidId": "bid", "adserverRequestId": "arid"}`))),
},
expectedError: nil,
},
"Includes sfp.js without iFrame busting logic if iFrame param is true": {
inputResponse: openrtb_ext.ExtImpSharethroughResponse{BidID: "bid", AdServerRequestID: "arid"},
inputResponse: []byte(`{"bidId": "bid", "adserverRequestId": "arid"}`),
inputParams: &StrAdSeverParams{Pkey: "pkey", Iframe: true},
expectedSuccess: []string{
`<script src="//native.sharethrough.com/assets/sfp.js"></script>`,
},
expectedError: nil,
},
"Includes sfp.js with iFrame busting logic if iFrame param is false": {
inputResponse: openrtb_ext.ExtImpSharethroughResponse{BidID: "bid", AdServerRequestID: "arid"},
inputResponse: []byte(`{"bidId": "bid", "adserverRequestId": "arid"}`),
inputParams: &StrAdSeverParams{Pkey: "pkey", Iframe: false},
expectedSuccess: []string{
`<script src="//native.sharethrough.com/assets/sfp-set-targeting.js"></script>`,
},
expectedError: nil,
},
"Includes sfp.js with iFrame busting logic if iFrame param is not provided": {
inputResponse: openrtb_ext.ExtImpSharethroughResponse{BidID: "bid", AdServerRequestID: "arid"},
inputResponse: []byte(`{"bidId": "bid", "adserverRequestId": "arid"}`),
inputParams: &StrAdSeverParams{Pkey: "pkey"},
expectedSuccess: []string{
`<script src="//native.sharethrough.com/assets/sfp-set-targeting.js"></script>`,
Expand All @@ -55,7 +58,10 @@ func TestGetAdMarkup(t *testing.T) {
t.Logf("Test case: %s\n", testName)
assert := assert.New(t)

outputSuccess, outputError := Util{}.getAdMarkup(test.inputResponse, test.inputParams)
var strResp openrtb_ext.ExtImpSharethroughResponse
_ = json.Unmarshal(test.inputResponse, &strResp)

outputSuccess, outputError := Util{}.getAdMarkup(test.inputResponse, strResp, test.inputParams)
for _, markup := range test.expectedSuccess {
assert.Contains(outputSuccess, markup)
}
Expand Down
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ func (cfg *Configuration) setDerivedDefaults() {
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderRhythmone, "https://sync.1rx.io/usersync2/rmphb?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Drhythmone%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5BRX_UUID%5D")
// openrtb_ext.BidderRTBHouse doesn't have a good default.
// openrtb_ext.BidderRubicon doesn't have a good default.
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSharethrough, "https://sharethrough.adnxs.com/getuid?"+url.QueryEscape(externalURL)+"/setuid?bidder=sharethrough&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&uid=$UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSharethrough, "https://match.sharethrough.com/FGMrCMMc/v1?redirectUri="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsharethrough%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSomoaudience, "https://publisher-east.mobileadtrading.com/usersync?ru="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsomoaudience%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSovrn, "https://ap.lijit.com/pixel?redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsovrn%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSonobi, "https://sync.go.sonobi.com/us.gif?loc="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsonobi%26consent_string%3D{{.GDPR}}%26gdpr%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D")
Expand Down
Loading

0 comments on commit 8759b67

Please sign in to comment.