Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin-P-Kerr committed Sep 13, 2019
2 parents f21041d + 94bf100 commit 92062e6
Show file tree
Hide file tree
Showing 243 changed files with 8,678 additions and 783 deletions.
21 changes: 21 additions & 0 deletions .github/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 7
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- bug
- feature request
- on hold
- Intent to implement
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ RUN apt-get update && \
apt-get -y upgrade && \
apt-get install -y wget
RUN cd /tmp && \
wget https://dl.google.com/go/go1.11.11.linux-amd64.tar.gz && \
tar -xf go1.11.11.linux-amd64.tar.gz && \
wget https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz && \
tar -xf go1.12.7.linux-amd64.tar.gz && \
mv go /usr/local
WORKDIR /go/src/github.com/prebid/prebid-server/
ENV GOROOT=/usr/local/go
ENV GOPATH=/go
ENV PATH=$GOPATH/bin:$GOROOT/bin:$PATH
RUN apt-get install -y git go-dep && \
RUN apt-get update && \
apt-get install -y git go-dep && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV CGO_ENABLED 0
COPY ./ ./
Expand Down
15 changes: 9 additions & 6 deletions adapters/adapterstest/test_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ import (
// }
//
func RunJSONBidderTest(t *testing.T, rootDir string, bidder adapters.Bidder) {
runTests(t, fmt.Sprintf("%s/exemplary", rootDir), bidder, false, false)
runTests(t, fmt.Sprintf("%s/supplemental", rootDir), bidder, true, false)
runTests(t, fmt.Sprintf("%s/amp", rootDir), bidder, true, true)
runTests(t, fmt.Sprintf("%s/exemplary", rootDir), bidder, false, false, false)
runTests(t, fmt.Sprintf("%s/supplemental", rootDir), bidder, true, false, false)
runTests(t, fmt.Sprintf("%s/amp", rootDir), bidder, true, true, false)
runTests(t, fmt.Sprintf("%s/video", rootDir), bidder, false, false, true)
}

// runTests runs all the *.json files in a directory. If allowErrors is false, and one of the test files
// expects errors from the bidder, then the test will fail.
func runTests(t *testing.T, directory string, bidder adapters.Bidder, allowErrors bool, isAmpTest bool) {
func runTests(t *testing.T, directory string, bidder adapters.Bidder, allowErrors, isAmpTest, isVideoTest bool) {
if specFiles, err := ioutil.ReadDir(directory); err == nil {
for _, specFile := range specFiles {
fileName := fmt.Sprintf("%s/%s", directory, specFile.Name())
Expand All @@ -69,7 +70,7 @@ func runTests(t *testing.T, directory string, bidder adapters.Bidder, allowError
if !allowErrors && specData.expectsErrors() {
t.Fatalf("Exemplary spec %s must not expect errors.", fileName)
}
runSpec(t, fileName, specData, bidder, isAmpTest)
runSpec(t, fileName, specData, bidder, isAmpTest, isVideoTest)
}
}
}
Expand Down Expand Up @@ -97,11 +98,13 @@ func loadFile(filename string) (*testSpec, error) {
// - That the Bidder's errors match the spec's expectations
//
// More assertions will almost certainly be added in the future, as bugs come up.
func runSpec(t *testing.T, filename string, spec *testSpec, bidder adapters.Bidder, isAmpTest bool) {
func runSpec(t *testing.T, filename string, spec *testSpec, bidder adapters.Bidder, isAmpTest, isVideoTest bool) {
reqInfo := adapters.ExtraRequestInfo{}
if isAmpTest {
// simulates AMP entry point
reqInfo.PbsEntryPoint = "amp"
} else if isVideoTest {
reqInfo.PbsEntryPoint = "video"
}
actualReqs, errs := bidder.MakeRequests(&spec.BidRequest, &reqInfo)
diffErrorLists(t, fmt.Sprintf("%s: MakeRequests", filename), errs, spec.MakeRequestErrors)
Expand Down
2 changes: 1 addition & 1 deletion adapters/adform/adform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func preparePrebidRequest(serverUrl string, t *testing.T) *pbs.PBSRequest {
pbsCookie := usersync.ParsePBSCookieFromRequest(prebidHttpRequest, &config.HostCookie{})
pbsCookie.TrySync("adform", adformTestData.buyerUID)
fakeWriter := httptest.NewRecorder()
pbsCookie.SetCookieOnResponse(fakeWriter, "", time.Minute)
pbsCookie.SetCookieOnResponse(fakeWriter, &config.HostCookie{Domain: ""}, time.Minute)
prebidHttpRequest.Header.Add("Cookie", fakeWriter.Header().Get("Set-Cookie"))

cacheClient, _ := dummycache.New()
Expand Down
265 changes: 265 additions & 0 deletions adapters/adkernel/adkernel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package adkernel

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"text/template"

"github.com/golang/glog"
"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/macros"
"github.com/prebid/prebid-server/openrtb_ext"
)

type adkernelAdapter struct {
EndpointTemplate template.Template
}

//MakeRequests prepares request information for prebid-server core
func (adapter *adkernelAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
errs := make([]error, 0, len(request.Imp))
if len(request.Imp) == 0 {
errs = append(errs, newBadInputError("No impression in the bid request"))
return nil, errs
}
imps, impExts, err := getImpressionsInfo(request.Imp)
if len(imps) == 0 {
return nil, err
}
errs = append(errs, err...)

pub2impressions, dispErrors := dispatchImpressions(imps, impExts)
if len(dispErrors) > 0 {
errs = append(errs, dispErrors...)
}
if len(pub2impressions) == 0 {
return nil, errs
}
result := make([]*adapters.RequestData, 0, len(pub2impressions))
for k, imps := range pub2impressions {
bidRequest, err := adapter.buildAdapterRequest(request, &k, imps)
if err != nil {
errs = append(errs, err)
} else {
result = append(result, bidRequest)
}
}
return result, errs
}

// getImpressionsInfo checks each impression for validity and returns impressions copy with corresponding exts
func getImpressionsInfo(imps []openrtb.Imp) ([]openrtb.Imp, []openrtb_ext.ExtImpAdkernel, []error) {
impsCount := len(imps)
errors := make([]error, 0, impsCount)
resImps := make([]openrtb.Imp, 0, impsCount)
resImpExts := make([]openrtb_ext.ExtImpAdkernel, 0, impsCount)

for _, imp := range imps {
impExt, err := getImpressionExt(&imp)
if err != nil {
errors = append(errors, err)
continue
}
if err := validateImpression(&imp, impExt); err != nil {
errors = append(errors, err)
continue
}
resImps = append(resImps, imp)
resImpExts = append(resImpExts, *impExt)
}
return resImps, resImpExts, errors
}

func validateImpression(imp *openrtb.Imp, impExt *openrtb_ext.ExtImpAdkernel) error {
if impExt.ZoneId < 1 {
return newBadInputError(fmt.Sprintf("Invalid zoneId value: %d. Ignoring imp id=%s", impExt.ZoneId, imp.ID))
}
if len(impExt.Host) == 0 {
return newBadInputError(fmt.Sprintf("Host is empty. Ignoring imp id=%s", imp.ID))
}
if imp.Video == nil && imp.Banner == nil {
return newBadInputError(fmt.Sprintf("Invalid imp id=%s. Expected imp.banner or imp.video", imp.ID))
}
return nil
}

//Group impressions by AdKernel-specific parameters `zoneId` & `host`
func dispatchImpressions(imps []openrtb.Imp, impsExt []openrtb_ext.ExtImpAdkernel) (map[openrtb_ext.ExtImpAdkernel][]openrtb.Imp, []error) {
res := make(map[openrtb_ext.ExtImpAdkernel][]openrtb.Imp)
errors := make([]error, 0)
for idx := range imps {
imp := imps[idx]
err := compatImpression(&imp)
if err != nil {
errors = append(errors, err)
continue
}
impExt := impsExt[idx]
if res[impExt] == nil {
res[impExt] = make([]openrtb.Imp, 0)
}
res[impExt] = append(res[impExt], imp)
}
return res, errors
}

//Alter impression info to comply with adkernel platform requirements
func compatImpression(imp *openrtb.Imp) error {
imp.Ext = nil //do not forward ext to adkernel platform
if imp.Banner != nil {
return compatBannerImpression(imp)
}
if imp.Video != nil {
return compatVideoImpression(imp)
}
return newBadInputError("Invalid impression")
}

func compatBannerImpression(imp *openrtb.Imp) error {
imp.Audio = nil
imp.Video = nil
imp.Native = nil
return nil
}

func compatVideoImpression(imp *openrtb.Imp) error {
imp.Banner = nil
imp.Audio = nil
imp.Native = nil
return nil
}

func getImpressionExt(imp *openrtb.Imp) (*openrtb_ext.ExtImpAdkernel, error) {
var bidderExt adapters.ExtImpBidder
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return nil, &errortypes.BadInput{
Message: err.Error(),
}
}
var adkernelExt openrtb_ext.ExtImpAdkernel
if err := json.Unmarshal(bidderExt.Bidder, &adkernelExt); err != nil {
return nil, &errortypes.BadInput{
Message: err.Error(),
}
}
return &adkernelExt, nil
}

func (adapter *adkernelAdapter) buildAdapterRequest(prebidBidRequest *openrtb.BidRequest, params *openrtb_ext.ExtImpAdkernel, imps []openrtb.Imp) (*adapters.RequestData, error) {
newBidRequest := createBidRequest(prebidBidRequest, params, imps)
reqJSON, err := json.Marshal(newBidRequest)
if err != nil {
return nil, err
}

headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")
headers.Add("x-openrtb-version", "2.5")

url, err := adapter.buildEndpointURL(params)
if err != nil {
return nil, err
}

return &adapters.RequestData{
Method: "POST",
Uri: url,
Body: reqJSON,
Headers: headers}, nil
}

func createBidRequest(prebidBidRequest *openrtb.BidRequest, params *openrtb_ext.ExtImpAdkernel, imps []openrtb.Imp) *openrtb.BidRequest {
bidRequest := *prebidBidRequest
bidRequest.Imp = imps
if bidRequest.Site != nil {
// Need to copy Site as Request is a shallow copy
siteCopy := *bidRequest.Site
bidRequest.Site = &siteCopy
bidRequest.Site.Publisher = nil
}
if bidRequest.App != nil {
// Need to copy App as Request is a shallow copy
appCopy := *bidRequest.App
bidRequest.App = &appCopy
bidRequest.App.Publisher = nil
}
return &bidRequest
}

// Builds endpoint url based on adapter-specific pub settings from imp.ext
func (adapter *adkernelAdapter) buildEndpointURL(params *openrtb_ext.ExtImpAdkernel) (string, error) {
endpointParams := macros.EndpointTemplateParams{Host: params.Host, ZoneID: strconv.Itoa(params.ZoneId)}
return macros.ResolveMacros(adapter.EndpointTemplate, endpointParams)
}

//MakeBids translates adkernel bid response to prebid-server specific format
func (adapter *adkernelAdapter) 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.StatusOK {
return nil, []error{
newBadServerResponseError(fmt.Sprintf("Unexpected http status code: %d", response.StatusCode)),
}
}
var bidResp openrtb.BidResponse
if err := json.Unmarshal(response.Body, &bidResp); err != nil {
return nil, []error{
newBadServerResponseError(fmt.Sprintf("Bad server response: %d", err)),
}
}
if len(bidResp.SeatBid) != 1 {
return nil, []error{
newBadServerResponseError(fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid))),
}
}

seatBid := bidResp.SeatBid[0]
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))

for i := 0; i < len(seatBid.Bid); i++ {
bid := seatBid.Bid[i]
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: getMediaTypeForImpID(bid.ImpID, internalRequest.Imp),
})
}
return bidResponse, nil
}

// getMediaTypeForImp figures out which media type this bid is for
func getMediaTypeForImpID(impID string, imps []openrtb.Imp) openrtb_ext.BidType {
for _, imp := range imps {
if imp.ID == impID && imp.Banner != nil {
return openrtb_ext.BidTypeBanner
}
}
return openrtb_ext.BidTypeVideo
}

func newBadInputError(message string) error {
return &errortypes.BadInput{
Message: message,
}
}

func newBadServerResponseError(message string) error {
return &errortypes.BadServerResponse{
Message: message,
}
}

// NewAdkernelAdapter to be called in prebid-server core to create Adkernel adapter instance
func NewAdkernelAdapter(endpointTemplate string) adapters.Bidder {
urlTemplate, err := template.New("endpointTemplate").Parse(endpointTemplate)
if err != nil {
glog.Fatal("Unable to parse endpoint url template")
return nil
}
return &adkernelAdapter{EndpointTemplate: *urlTemplate}
}
11 changes: 11 additions & 0 deletions adapters/adkernel/adkernel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package adkernel

import (
"testing"

"github.com/prebid/prebid-server/adapters/adapterstest"
)

func TestJsonSamples(t *testing.T) {
adapterstest.RunJSONBidderTest(t, "adkerneltest", NewAdkernelAdapter("http://{{.Host}}/hb?zone={{.ZoneID}}"))
}
Loading

0 comments on commit 92062e6

Please sign in to comment.