From dcdddfa883df3d65c212cc14c9a4d80762273f7c Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Wed, 10 Jul 2024 01:13:27 +0530 Subject: [PATCH 01/10] Create a basic insticator adaptor (#3) * init insticator adaptor * update modules * add mediaType for bids * update insticator adaptor with tests * update insticator for test cases * fix test cases * update InstAdapter * update insticator adaptor * fix test cases for adUnitId * update insticator adapter type * Updates - add currency converter support - Add video validation support * remove default plcmt and placement * add more test cases * update for publisher ID * fix tests --- adapters/insticator/insticator.go | 509 ++++++++++++++++++ adapters/insticator/insticator_test.go | 21 + .../exemplary/multi-format.json | 121 +++++ .../insticatortest/exemplary/site-banner.json | 118 ++++ .../insticatortest/exemplary/site-video.json | 130 +++++ .../multi-imp-mixed-validation.json | 133 +++++ .../supplemental/status-not-ok.json | 86 +++ .../supplemental/video-validation-fail.json | 33 ++ adapters/insticator/params_test.go | 51 ++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_insticator.go | 7 + static/bidder-info/insticator.yaml | 19 + static/bidder-params/insticator.json | 19 + 14 files changed, 1251 insertions(+) create mode 100644 adapters/insticator/insticator.go create mode 100644 adapters/insticator/insticator_test.go create mode 100644 adapters/insticator/insticatortest/exemplary/multi-format.json create mode 100644 adapters/insticator/insticatortest/exemplary/site-banner.json create mode 100644 adapters/insticator/insticatortest/exemplary/site-video.json create mode 100644 adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json create mode 100644 adapters/insticator/insticatortest/supplemental/status-not-ok.json create mode 100644 adapters/insticator/insticatortest/supplemental/video-validation-fail.json create mode 100644 adapters/insticator/params_test.go create mode 100644 openrtb_ext/imp_insticator.go create mode 100644 static/bidder-info/insticator.yaml create mode 100644 static/bidder-params/insticator.json diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go new file mode 100644 index 00000000000..9b1b5066933 --- /dev/null +++ b/adapters/insticator/insticator.go @@ -0,0 +1,509 @@ +package insticator + +import ( + "encoding/json" + "fmt" + "log" + "math" + "net/http" + "reflect" + "strconv" + "strings" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/adapters" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/errortypes" + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +// type adapter struct { +// endpoint string +// } + +type Ext struct { + Insticator impInsticatorExt `json:"insticator"` +} + +type insticatorUserExt struct { + Eids []openrtb2.EID `json:"eids,omitempty"` + Data json.RawMessage `json:"data,omitempty"` + Consent string `json:"consent,omitempty"` +} + +type impInsticatorExt struct { + AdUnitId string `json:"adUnitId,omitempty"` + PublisherId string `json:"publisherId,omitempty"` +} + +type adapter struct { + endpoint string +} + +type reqExt struct { + Insticator *reqInsticatorExt `json:"insticator,omitempty"` +} + +type reqInsticatorExt struct { + Caller []InsticatorCaller `json:"caller,omitempty"` +} + +type InsticatorCaller struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` +} + +// CALLER Info used to track Prebid Server +// as one of the hops in the request to exchange +var CALLER = InsticatorCaller{"Prebid-Server", "n/a"} + +type bidExt struct { + Insticator bidInsticatorExt `json:"insticator,omitempty"` +} + +type bidInsticatorExt struct { + MediaType string `json:"mediaType,omitempty"` +} + +// Placeholder for the actual openrtb2.Video struct +type Video struct { + W *int `json:"w"` + H *int `json:"h"` + MIMEs []string `json:"mimes"` + Placement int `json:"placement"` + Plcmt int `json:"plcmt"` + MinDuration *int `json:"minduration"` + MaxDuration *int `json:"maxduration"` + Protocols []int `json:"protocols"` + StartDelay *int `json:"startdelay"` + Linearity *int `json:"linearity"` + Skip *int `json:"skip"` + SkipMin *int `json:"skipmin"` + SkipAfter *int `json:"skipafter"` + Sequence *int `json:"sequence"` + Battr []int `json:"battr"` + MaxExtended *int `json:"maxextended"` + MinBitrate *int `json:"minbitrate"` + MaxBitrate *int `json:"maxbitrate"` + PlaybackMethod []int `json:"playbackmethod"` + PlaybackEnd *int `json:"playbackend"` + Delivery []int `json:"delivery"` + Pos *int `json:"pos"` + API []int `json:"api"` +} + +type BadInput struct { + Message string +} + +func (e *BadInput) Error() string { + return e.Message +} + +// Validation functions +func isInteger(value interface{}) bool { + switch v := value.(type) { + case int: + return true + case float64: + return v == float64(int(v)) + case string: + _, err := strconv.Atoi(v) + return err == nil + default: + return false + } +} + +func isArrayOfNums(value interface{}) bool { + switch v := value.(type) { + case []int: + return true + case []float64: + for _, num := range v { + if num != float64(int(num)) { + return false + } + } + return true + case []string: + for _, str := range v { + if _, err := strconv.Atoi(str); err != nil { + return false + } + } + return true + default: + return false + } +} + +// Define valid values +var validLinearity = map[int]bool{1: true} +var validSkip = map[int]bool{0: true, 1: true} +var validPlaybackEnd = map[int]bool{1: true, 2: true, 3: true} +var validPos = map[int]bool{0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true} + +// Map parameters to validation functions +var optionalVideoParams = map[string]func(interface{}) bool{ + "minduration": isInteger, + "maxduration": isInteger, + "protocols": isArrayOfNums, + "startdelay": isInteger, + "linearity": func(value interface{}) bool { return isInteger(value) && validLinearity[toInt(value)] }, + "skip": func(value interface{}) bool { return isInteger(value) && validSkip[toInt(value)] }, + "skipmin": isInteger, + "skipafter": isInteger, + "sequence": isInteger, + "battr": isArrayOfNums, + "maxextended": isInteger, + "minbitrate": isInteger, + "maxbitrate": isInteger, + "playbackmethod": isArrayOfNums, + "playbackend": func(value interface{}) bool { return isInteger(value) && validPlaybackEnd[toInt(value)] }, + "delivery": isArrayOfNums, + "pos": func(value interface{}) bool { return isInteger(value) && validPos[toInt(value)] }, + "api": isArrayOfNums, +} + +// Helper function to convert interface to int +func toInt(value interface{}) int { + switch v := value.(type) { + case int: + return v + case float64: + return int(v) + case string: + if i, err := strconv.Atoi(v); err == nil { + return i + } + } + return 0 +} + +// Builder builds a new insticatorance of the Foo adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +// getMediaTypeForImp figures out which media type this bid is for +func getMediaTypeForBid(bid *openrtb2.Bid) openrtb_ext.BidType { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo + default: + return openrtb_ext.BidTypeBanner + } +} + +func getBidType(ext bidExt) openrtb_ext.BidType { + if ext.Insticator.MediaType == "video" { + return openrtb_ext.BidTypeVideo + } + + return openrtb_ext.BidTypeBanner +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + + log.Printf("IN makeRequests") + + var errs []error + var adapterRequests []*adapters.RequestData + var groupedImps = make(map[string][]openrtb2.Imp) + + // Construct request extension common to all imps + // NOTE: not blocking adapter requests on errors + // since request extension is optional. + reqExt, err := makeReqExt(request) + if err != nil { + errs = append(errs, err) + } + request.Ext = reqExt + + for i := 0; i < len(request.Imp); i++ { + if impCopy, err := makeImps(request.Imp[i]); err == nil { + var impExt Ext + // Populate site.publisher.id from imp extension only once + if request.Site != nil && i == 0 { + populateSitePublisherId(&impCopy, request.Site) + } + + // group together the imp hacing insticator adUnitId. However let's not block request creation. + if err := json.Unmarshal(impCopy.Ext, &impExt); err == nil { + impKey := impExt.Insticator.AdUnitId + + resolvedBidFloor, errFloor := resolveBidFloor(impCopy.BidFloor, impCopy.BidFloorCur, requestInfo) + if errFloor != nil { + errs = append(errs, errFloor) + } else { + if resolvedBidFloor > 0 { + impCopy.BidFloor = resolvedBidFloor + impCopy.BidFloorCur = "USD" + } + } + + groupedImps[impKey] = append(groupedImps[impKey], impCopy) + } else { + errs = append(errs, err) + } + } else { + errs = append(errs, err) + } + } + + for _, impList := range groupedImps { + if adapterReq, err := a.makeRequest(*request, impList); err == nil { + adapterRequests = append(adapterRequests, adapterReq) + } else { + errs = append(errs, err) + } + } + return adapterRequests, errs +} + +func (a *adapter) makeRequest(request openrtb2.BidRequest, impList []openrtb2.Imp) (*adapters.RequestData, error) { + request.Imp = impList + + // Last Step + reqJSON, err := json.Marshal(request) + if err != nil { + return nil, err + } + // log reqJson + // log.Printf("reqJSON Before makerequest: %s", reqJSON) + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + return &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if responseData.StatusCode == http.StatusNoContent { + return nil, nil + } + + if responseData.StatusCode == http.StatusBadRequest { + err := &errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + } + return nil, []error{err} + } + + if responseData.StatusCode != http.StatusOK { + err := &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + } + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := json.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bid := &seatBid.Bid[i] + bidType := getMediaTypeForBid(bid) + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func makeImps(imp openrtb2.Imp) (openrtb2.Imp, error) { + if imp.Banner == nil && imp.Video == nil { + return openrtb2.Imp{}, &errortypes.BadInput{ + Message: fmt.Sprintf("Imp ID %s must have at least one of [Banner, Video] defined", imp.ID), + } + } + + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return openrtb2.Imp{}, &errortypes.BadInput{ + Message: err.Error(), + } + } + + var insticatorExt openrtb_ext.ExtImpInsticator + if err := json.Unmarshal(bidderExt.Bidder, &insticatorExt); err != nil { + return openrtb2.Imp{}, &errortypes.BadInput{ + Message: err.Error(), + } + } + + var impExt Ext + impExt.Insticator.AdUnitId = insticatorExt.AdUnitId + impExt.Insticator.PublisherId = insticatorExt.PublisherId + + impExtJSON, err := json.Marshal(impExt) + if err != nil { + return openrtb2.Imp{}, &errortypes.BadInput{ + Message: err.Error(), + } + } + + imp.Ext = impExtJSON + + // Validate Video if it exists + if imp.Video != nil { + videoCopy, err := validateVideoParams(imp.Video) + + imp.Video = videoCopy + + if err != nil { + return openrtb2.Imp{}, &errortypes.BadInput{ + Message: err.Error(), + } + } + } + + return imp, nil +} + +func validateVideoParams(video *openrtb2.Video) (*openrtb2.Video, error) { + videoCopy := *video + if (videoCopy.W == nil || *videoCopy.W == 0) || + (videoCopy.H == nil || *videoCopy.H == 0) || + videoCopy.MIMEs == nil { + + return nil, &errortypes.BadInput{ + Message: "One or more invalid or missing video field(s) w, h, mimes", + } + } + + // Validate optional parameters and remove invalid ones + cleanedVideo, err := validateOptionalVideoParams(&videoCopy) + if err != nil { + return nil, err + } + + return cleanedVideo, nil +} + +func makeReqExt(request *openrtb2.BidRequest) ([]byte, error) { + var reqExt reqExt + + if len(request.Ext) > 0 { + if err := json.Unmarshal(request.Ext, &reqExt); err != nil { + return nil, err + } + } + + if reqExt.Insticator == nil { + reqExt.Insticator = &reqInsticatorExt{} + } + + if reqExt.Insticator.Caller == nil { + reqExt.Insticator.Caller = make([]InsticatorCaller, 0) + } + + reqExt.Insticator.Caller = append(reqExt.Insticator.Caller, CALLER) + + return json.Marshal(reqExt) +} + +func resolveBidFloor(bidFloor float64, bidFloorCur string, reqInfo *adapters.ExtraRequestInfo) (float64, error) { + if bidFloor > 0 && bidFloorCur != "" && strings.ToUpper(bidFloorCur) != "USD" { + floor, err := reqInfo.ConvertCurrency(bidFloor, bidFloorCur, "USD") + return roundTo4Decimals(floor), err + } + + return bidFloor, nil +} + +// roundTo4Decimals function +func roundTo4Decimals(amount float64) float64 { + return math.Round(amount*10000) / 10000 +} + +func validateOptionalVideoParams(video *openrtb2.Video) (*openrtb2.Video, error) { + v := reflect.ValueOf(video).Elem() + t := v.Type() + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fieldValue := v.Field(i) + + // Convert the field name to camelCase for matching in optionalVideoParams map + jsonTag := field.Tag.Get("json") + if jsonTag == "" { + jsonTag = toCamelCase(field.Name) + } + + // Skip fields that are not in optionalVideoParams + validator, exists := optionalVideoParams[jsonTag] + if !exists { + continue + } + + // Check if the field value is zero/nil and skip if true + if isZeroOrNil(fieldValue) { + continue + } + + // Validate the field value + if !validator(fieldValue.Interface()) { + // If invalid, set the field to zero value + fieldValue.Set(reflect.Zero(fieldValue.Type())) + } + } + return video, nil +} + +// Helper function to convert field name to camelCase +func toCamelCase(s string) string { + if s == "" { + return s + } + return strings.ToLower(string(s[0])) + s[1:] +} + +// Helper function to check if a value is zero or nil +func isZeroOrNil(value reflect.Value) bool { + switch value.Kind() { + case reflect.Ptr, reflect.Interface: + return value.IsNil() + case reflect.Slice, reflect.Array: + return value.Len() == 0 + case reflect.Map: + return len(value.MapKeys()) == 0 + default: + return value.IsZero() + } +} + +// populate publisherId to site object from imp extension +func populateSitePublisherId(imp *openrtb2.Imp, site *openrtb2.Site) { + var ext Ext + + if site.Publisher == nil { + site.Publisher = &openrtb2.Publisher{} + log.Printf("Created Publisher object in Site") + } + + if err := json.Unmarshal(imp.Ext, &ext); err == nil { + site.Publisher.ID = ext.Insticator.PublisherId + } else { + log.Printf("Error unmarshalling imp extension: %v", err) + } +} diff --git a/adapters/insticator/insticator_test.go b/adapters/insticator/insticator_test.go new file mode 100644 index 00000000000..e929402b822 --- /dev/null +++ b/adapters/insticator/insticator_test.go @@ -0,0 +1,21 @@ +package insticator + +import ( + "testing" + + "github.com/prebid/prebid-server/v2/adapters/adapterstest" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderInsticator, config.Adapter{ + Endpoint: "https://ex.ingage.tech/v1/prebidserver"}, + config.Server{ExternalUrl: "https://ex.ingage.tech/v1/prebidserver", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "insticatortest", bidder) +} diff --git a/adapters/insticator/insticatortest/exemplary/multi-format.json b/adapters/insticator/insticatortest/exemplary/multi-format.json new file mode 100644 index 00000000000..9bcf7873e86 --- /dev/null +++ b/adapters/insticator/insticatortest/exemplary/multi-format.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "video": { + "w": 728, + "h": 90, + "protocols": [2], + "playbackmethod": [2], + "mimes": ["foo", "bar"] + }, + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "video": { + "w": 728, + "h": 90, + "protocols": [2], + "playbackmethod": [2], + "mimes": ["foo", "bar"] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "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": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] + } + \ No newline at end of file diff --git a/adapters/insticator/insticatortest/exemplary/site-banner.json b/adapters/insticator/insticatortest/exemplary/site-banner.json new file mode 100644 index 00000000000..783bcf4dec2 --- /dev/null +++ b/adapters/insticator/insticatortest/exemplary/site-banner.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }] + } + ], + "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": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/insticator/insticatortest/exemplary/site-video.json b/adapters/insticator/insticatortest/exemplary/site-video.json new file mode 100644 index 00000000000..7ed9f846a02 --- /dev/null +++ b/adapters/insticator/insticatortest/exemplary/site-video.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 728, + "h": 90, + "protocols": [2], + "placement": 1, + "startdelay": -2, + "playbackmethod": [2], + "mimes": ["foo", "bar"] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "video": { + "w": 728, + "h": 90, + "protocols": [2], + "placement": 1, + "startdelay": -2, + "playbackmethod": [2], + "mimes": ["foo", "bar"] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-vast-ad", + "mtype": 2, + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "video" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-vast-ad", + "crid": "crid_10", + "w": 728, + "mtype": 2, + "h": 90, + "ext": { + "insticator": { + "mediaType": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json new file mode 100644 index 00000000000..6f6cc5e3545 --- /dev/null +++ b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + }, + { + "id": "test-imp-id2", + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Imp ID test-imp-id2 must have at least one of [Banner, Video] defined", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } + \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/status-not-ok.json b/adapters/insticator/insticatortest/supplemental/status-not-ok.json new file mode 100644 index 00000000000..814e2eeff2c --- /dev/null +++ b/adapters/insticator/insticatortest/supplemental/status-not-ok.json @@ -0,0 +1,86 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "fake-invalid-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "fake-invalid-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 400, + "body": { + "error": { + "message": "Validation failed", + "details": [ + { + "message": "site.id is invalid" + } + ] + } + } + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info.", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/insticator/insticatortest/supplemental/video-validation-fail.json b/adapters/insticator/insticatortest/supplemental/video-validation-fail.json new file mode 100644 index 00000000000..553b0f68c67 --- /dev/null +++ b/adapters/insticator/insticatortest/supplemental/video-validation-fail.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "expectedMakeRequestsErrors": [ + { + "value": "One or more invalid or missing video field(s) w, h, mimes", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/insticator/params_test.go b/adapters/insticator/params_test.go new file mode 100644 index 00000000000..ba4465ea4a3 --- /dev/null +++ b/adapters/insticator/params_test.go @@ -0,0 +1,51 @@ +package insticator + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/Insticator.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.Insticator + +// TestValidParams makes sure that the Insticator 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.BidderInsticator, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Insticator params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the Insticator 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.BidderInsticator, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"publisherId": "inview", "adUnitId": "fakesiteid1"}`, + `{"publisherId": "siab", "adUnitId": "fakesiteid2"}`, + `{"publisherId": "inview", "adUnitId": "foo.ba"}`, +} + +var invalidParams = []string{ + `{"publisherId": "inview"}`, + `{"publisherId": 123, "adUnitId": "fakesiteid2"}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index fdbc0dbf213..5c1738073ea 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -103,6 +103,7 @@ import ( "github.com/prebid/prebid-server/v2/adapters/improvedigital" "github.com/prebid/prebid-server/v2/adapters/infytv" "github.com/prebid/prebid-server/v2/adapters/inmobi" + "github.com/prebid/prebid-server/v2/adapters/insticator" "github.com/prebid/prebid-server/v2/adapters/interactiveoffers" "github.com/prebid/prebid-server/v2/adapters/invibes" "github.com/prebid/prebid-server/v2/adapters/iqx" @@ -320,6 +321,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderImprovedigital: improvedigital.Builder, openrtb_ext.BidderInfyTV: infytv.Builder, openrtb_ext.BidderInMobi: inmobi.Builder, + openrtb_ext.BidderInsticator: insticator.Builder, openrtb_ext.BidderInteractiveoffers: interactiveoffers.Builder, openrtb_ext.BidderInvibes: invibes.Builder, openrtb_ext.BidderIQX: iqx.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 5af05d90b6f..282fb314947 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -120,6 +120,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderImprovedigital, BidderInfyTV, BidderInMobi, + BidderInsticator, BidderInteractiveoffers, BidderInvibes, BidderIQX, @@ -436,6 +437,7 @@ const ( BidderImprovedigital BidderName = "improvedigital" BidderInfyTV BidderName = "infytv" BidderInMobi BidderName = "inmobi" + BidderInsticator BidderName = "insticator" BidderInteractiveoffers BidderName = "interactiveoffers" BidderInvibes BidderName = "invibes" BidderIQX BidderName = "iqx" diff --git a/openrtb_ext/imp_insticator.go b/openrtb_ext/imp_insticator.go new file mode 100644 index 00000000000..cb33223dfec --- /dev/null +++ b/openrtb_ext/imp_insticator.go @@ -0,0 +1,7 @@ +package openrtb_ext + +// ExtImpInsticator defines the contract for bidrequest.imp[i].ext.prebid.bidder.insticator +type ExtImpInsticator struct { + AdUnitId string `json:"adUnitId,omitempty"` + PublisherId string `json:"publisherId,omitempty"` +} diff --git a/static/bidder-info/insticator.yaml b/static/bidder-info/insticator.yaml new file mode 100644 index 00000000000..e9e6651433a --- /dev/null +++ b/static/bidder-info/insticator.yaml @@ -0,0 +1,19 @@ +endpoint: "http://ex.hunchme.com/v1/prebidserver?debug=true" +geoscope: + - global +maintainer: + email: "predid@insticator.com" +gvlVendorID: 910 +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + iframe: + url: "https://usync.hunchme.com?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + userMacro: "" \ No newline at end of file diff --git a/static/bidder-params/insticator.json b/static/bidder-params/insticator.json new file mode 100644 index 00000000000..586a6e2c83f --- /dev/null +++ b/static/bidder-params/insticator.json @@ -0,0 +1,19 @@ + +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Insticator Adapter Params", + "description": "A schema which validates params accepted by Insticator", + + "type": "object", + "properties": { + "adUnitId": { + "type": "string", + "description": "Ad Unit Id" + }, + "publisherId": { + "type": "string", + "description": "Publisher Id" + } + }, + "required": ["adUnitId", "publisherId"] + } \ No newline at end of file From 56feaa02d3cb6685b6836dd2073cd071d090b81d Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Wed, 10 Jul 2024 02:01:01 +0530 Subject: [PATCH 02/10] Update insticator.yaml --- static/bidder-info/insticator.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/insticator.yaml b/static/bidder-info/insticator.yaml index e9e6651433a..0912d647acf 100644 --- a/static/bidder-info/insticator.yaml +++ b/static/bidder-info/insticator.yaml @@ -1,6 +1,8 @@ -endpoint: "http://ex.hunchme.com/v1/prebidserver?debug=true" +endpoint: "https://ex.hunchme.com/v1/prebidserver?debug=true" geoscope: - global +disable: + - false maintainer: email: "predid@insticator.com" gvlVendorID: 910 @@ -16,4 +18,4 @@ capabilities: userSync: iframe: url: "https://usync.hunchme.com?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" - userMacro: "" \ No newline at end of file + userMacro: "" From db6d2c315d0946810f2ca1d767ce09d908ffc351 Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Wed, 10 Jul 2024 20:54:59 +0530 Subject: [PATCH 03/10] add multi-imps testJson (#6) --- adapters/insticator/insticator.go | 27 +- .../insticatortest/exemplary/multi-imps.json | 329 ++++++++++++++++++ 2 files changed, 346 insertions(+), 10 deletions(-) create mode 100644 adapters/insticator/insticatortest/exemplary/multi-imps.json diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index 9b1b5066933..c1d421fb9bd 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -211,19 +211,15 @@ func getBidType(ext bidExt) openrtb_ext.BidType { func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - log.Printf("IN makeRequests") - var errs []error var adapterRequests []*adapters.RequestData var groupedImps = make(map[string][]openrtb2.Imp) - // Construct request extension common to all imps - // NOTE: not blocking adapter requests on errors - // since request extension is optional. reqExt, err := makeReqExt(request) if err != nil { errs = append(errs, err) } + request.Ext = reqExt for i := 0; i < len(request.Imp); i++ { @@ -270,16 +266,29 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte func (a *adapter) makeRequest(request openrtb2.BidRequest, impList []openrtb2.Imp) (*adapters.RequestData, error) { request.Imp = impList - // Last Step reqJSON, err := json.Marshal(request) if err != nil { return nil, err } - // log reqJson - // log.Printf("reqJSON Before makerequest: %s", reqJSON) headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + if request.Device != nil { + if len(request.Device.UA) > 0 { + headers.Add("User-Agent", request.Device.UA) + } + + if len(request.Device.IPv6) > 0 { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + + if len(request.Device.IP) > 0 { + headers.Add("X-Forwarded-For", request.Device.IP) + headers.Add("IP", request.Device.IP) + } + } return &adapters.RequestData{ Method: "POST", @@ -376,7 +385,6 @@ func makeImps(imp openrtb2.Imp) (openrtb2.Imp, error) { } } } - return imp, nil } @@ -498,7 +506,6 @@ func populateSitePublisherId(imp *openrtb2.Imp, site *openrtb2.Site) { if site.Publisher == nil { site.Publisher = &openrtb2.Publisher{} - log.Printf("Created Publisher object in Site") } if err := json.Unmarshal(imp.Ext, &ext); err == nil { diff --git a/adapters/insticator/insticatortest/exemplary/multi-imps.json b/adapters/insticator/insticatortest/exemplary/multi-imps.json new file mode 100644 index 00000000000..9d311c16acd --- /dev/null +++ b/adapters/insticator/insticatortest/exemplary/multi-imps.json @@ -0,0 +1,329 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + }, + { + "id": "test-imp-id3", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + }, + { + "id": "test-imp-id4", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "siab", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + }, + { + "id":"test-imp-id2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + }, + { + "id":"test-imp-id3", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "inview", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id1","test-imp-id2", "test-imp-id3"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.600000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id3", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + } + ] + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id4", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "siab", + "publisherId": "test-publisher-id" + } + } + } + ], + "site": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id4"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id4", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + } + ] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.6, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id3", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id4", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } + \ No newline at end of file From b751ff9d37a191bad4e98836f843c5f741c3d674 Mon Sep 17 00:00:00 2001 From: Shubham <127132399+shubhamc-ins@users.noreply.github.com> Date: Wed, 10 Jul 2024 23:38:55 +0530 Subject: [PATCH 04/10] Instissp 790 create a basic insticator go lang adapter new (#7) * add multi-imps testJson * fix pubId parsing for request --- adapters/insticator/insticator.go | 28 ++-- .../insticatortest/exemplary/app-banner.json | 119 ++++++++++++++++ .../insticatortest/exemplary/app-video.json | 131 ++++++++++++++++++ 3 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 adapters/insticator/insticatortest/exemplary/app-banner.json create mode 100644 adapters/insticator/insticatortest/exemplary/app-video.json diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index c1d421fb9bd..2f7c10e3246 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -227,7 +227,9 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte var impExt Ext // Populate site.publisher.id from imp extension only once if request.Site != nil && i == 0 { - populateSitePublisherId(&impCopy, request.Site) + populatePublisherId(&impCopy, request) + } else if request.App != nil && i == 0 { + populatePublisherId(&impCopy, request) } // group together the imp hacing insticator adUnitId. However let's not block request creation. @@ -500,17 +502,25 @@ func isZeroOrNil(value reflect.Value) bool { } } -// populate publisherId to site object from imp extension -func populateSitePublisherId(imp *openrtb2.Imp, site *openrtb2.Site) { +// populate publisherId to site/app object from imp extension +func populatePublisherId(imp *openrtb2.Imp, request *openrtb2.BidRequest) { var ext Ext - if site.Publisher == nil { - site.Publisher = &openrtb2.Publisher{} + if request.Site != nil && request.Site.Publisher == nil { + request.Site.Publisher = &openrtb2.Publisher{} + if err := json.Unmarshal(imp.Ext, &ext); err == nil { + request.Site.Publisher.ID = ext.Insticator.PublisherId + } else { + log.Printf("Error unmarshalling imp extension: %v", err) + } } - if err := json.Unmarshal(imp.Ext, &ext); err == nil { - site.Publisher.ID = ext.Insticator.PublisherId - } else { - log.Printf("Error unmarshalling imp extension: %v", err) + if request.App != nil && request.App.Publisher == nil { + request.App.Publisher = &openrtb2.Publisher{} + if err := json.Unmarshal(imp.Ext, &ext); err == nil { + request.App.Publisher.ID = ext.Insticator.PublisherId + } else { + log.Printf("Error unmarshalling imp extension: %v", err) + } } } diff --git a/adapters/insticator/insticatortest/exemplary/app-banner.json b/adapters/insticator/insticatortest/exemplary/app-banner.json new file mode 100644 index 00000000000..503689a899b --- /dev/null +++ b/adapters/insticator/insticatortest/exemplary/app-banner.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "app": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "app": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }] + } + ], + "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": "crid_10", + "w": 728, + "h": 90, + "mtype": 1, + "ext": { + "insticator": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } + \ No newline at end of file diff --git a/adapters/insticator/insticatortest/exemplary/app-video.json b/adapters/insticator/insticatortest/exemplary/app-video.json new file mode 100644 index 00000000000..1b68238ff7a --- /dev/null +++ b/adapters/insticator/insticatortest/exemplary/app-video.json @@ -0,0 +1,131 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 728, + "h": 90, + "protocols": [2], + "placement": 1, + "startdelay": -2, + "playbackmethod": [2], + "mimes": ["foo", "bar"] + }, + "ext": { + "bidder": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "app": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ex.ingage.tech/v1/prebidserver", + "body": { + "ext": { + "insticator": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id", + "video": { + "w": 728, + "h": 90, + "protocols": [2], + "placement": 1, + "startdelay": -2, + "playbackmethod": [2], + "mimes": ["foo", "bar"] + }, + "ext": { + "insticator": { + "adUnitId": "fake-site-id", + "publisherId": "test-publisher-id" + } + } + } + ], + "app": { + "publisher": { + "id": "test-publisher-id" + } + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "insticator", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-vast-ad", + "mtype": 2, + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "insticator": { + "mediaType": "video" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-vast-ad", + "crid": "crid_10", + "w": 728, + "mtype": 2, + "h": 90, + "ext": { + "insticator": { + "mediaType": "video" + } + } + }, + "type": "video" + } + ] + } + ] + } + \ No newline at end of file From 92e859af6b9c9d7714ddad970afec41e93adc272 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Wed, 10 Jul 2024 23:53:00 +0530 Subject: [PATCH 05/10] update insticator yaml --- static/bidder-info/insticator.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/static/bidder-info/insticator.yaml b/static/bidder-info/insticator.yaml index 0912d647acf..2f93324f6de 100644 --- a/static/bidder-info/insticator.yaml +++ b/static/bidder-info/insticator.yaml @@ -1,8 +1,4 @@ -endpoint: "https://ex.hunchme.com/v1/prebidserver?debug=true" -geoscope: - - global -disable: - - false +endpoint: "https://ex.ingage.tech/v1/prebidserver" maintainer: email: "predid@insticator.com" gvlVendorID: 910 @@ -17,5 +13,5 @@ capabilities: - video userSync: iframe: - url: "https://usync.hunchme.com?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" + url: "https://usync.ingage.tech?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}}" userMacro: "" From 24d9b3976fab7c8ab0de396e93b8e9ce92bf80c2 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Mon, 12 Aug 2024 19:07:21 +0530 Subject: [PATCH 06/10] update insticator bid adaptor | remove validations | fixed interfaces --- adapters/insticator/insticator.go | 260 ++---------------- .../multi-imp-mixed-validation.json | 15 - .../supplemental/status-not-ok.json | 2 +- 3 files changed, 24 insertions(+), 253 deletions(-) diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index 2f7c10e3246..b8f79cf6e09 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -2,12 +2,9 @@ package insticator import ( "encoding/json" - "fmt" "log" "math" "net/http" - "reflect" - "strconv" "strings" "github.com/prebid/openrtb/v20/openrtb2" @@ -17,23 +14,13 @@ import ( "github.com/prebid/prebid-server/v2/openrtb_ext" ) -// type adapter struct { -// endpoint string -// } - -type Ext struct { +type ext struct { Insticator impInsticatorExt `json:"insticator"` } -type insticatorUserExt struct { - Eids []openrtb2.EID `json:"eids,omitempty"` - Data json.RawMessage `json:"data,omitempty"` - Consent string `json:"consent,omitempty"` -} - type impInsticatorExt struct { - AdUnitId string `json:"adUnitId,omitempty"` - PublisherId string `json:"publisherId,omitempty"` + AdUnitId string `json:"adUnitId"` + PublisherId string `json:"publisherId"` } type adapter struct { @@ -45,17 +32,17 @@ type reqExt struct { } type reqInsticatorExt struct { - Caller []InsticatorCaller `json:"caller,omitempty"` + Caller []insticatorCaller `json:"caller,omitempty"` } -type InsticatorCaller struct { +type insticatorCaller struct { Name string `json:"name,omitempty"` Version string `json:"version,omitempty"` } -// CALLER Info used to track Prebid Server +// caller Info used to track Prebid Server // as one of the hops in the request to exchange -var CALLER = InsticatorCaller{"Prebid-Server", "n/a"} +var caller = insticatorCaller{"Prebid-Server", "n/a"} type bidExt struct { Insticator bidInsticatorExt `json:"insticator,omitempty"` @@ -65,122 +52,6 @@ type bidInsticatorExt struct { MediaType string `json:"mediaType,omitempty"` } -// Placeholder for the actual openrtb2.Video struct -type Video struct { - W *int `json:"w"` - H *int `json:"h"` - MIMEs []string `json:"mimes"` - Placement int `json:"placement"` - Plcmt int `json:"plcmt"` - MinDuration *int `json:"minduration"` - MaxDuration *int `json:"maxduration"` - Protocols []int `json:"protocols"` - StartDelay *int `json:"startdelay"` - Linearity *int `json:"linearity"` - Skip *int `json:"skip"` - SkipMin *int `json:"skipmin"` - SkipAfter *int `json:"skipafter"` - Sequence *int `json:"sequence"` - Battr []int `json:"battr"` - MaxExtended *int `json:"maxextended"` - MinBitrate *int `json:"minbitrate"` - MaxBitrate *int `json:"maxbitrate"` - PlaybackMethod []int `json:"playbackmethod"` - PlaybackEnd *int `json:"playbackend"` - Delivery []int `json:"delivery"` - Pos *int `json:"pos"` - API []int `json:"api"` -} - -type BadInput struct { - Message string -} - -func (e *BadInput) Error() string { - return e.Message -} - -// Validation functions -func isInteger(value interface{}) bool { - switch v := value.(type) { - case int: - return true - case float64: - return v == float64(int(v)) - case string: - _, err := strconv.Atoi(v) - return err == nil - default: - return false - } -} - -func isArrayOfNums(value interface{}) bool { - switch v := value.(type) { - case []int: - return true - case []float64: - for _, num := range v { - if num != float64(int(num)) { - return false - } - } - return true - case []string: - for _, str := range v { - if _, err := strconv.Atoi(str); err != nil { - return false - } - } - return true - default: - return false - } -} - -// Define valid values -var validLinearity = map[int]bool{1: true} -var validSkip = map[int]bool{0: true, 1: true} -var validPlaybackEnd = map[int]bool{1: true, 2: true, 3: true} -var validPos = map[int]bool{0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true} - -// Map parameters to validation functions -var optionalVideoParams = map[string]func(interface{}) bool{ - "minduration": isInteger, - "maxduration": isInteger, - "protocols": isArrayOfNums, - "startdelay": isInteger, - "linearity": func(value interface{}) bool { return isInteger(value) && validLinearity[toInt(value)] }, - "skip": func(value interface{}) bool { return isInteger(value) && validSkip[toInt(value)] }, - "skipmin": isInteger, - "skipafter": isInteger, - "sequence": isInteger, - "battr": isArrayOfNums, - "maxextended": isInteger, - "minbitrate": isInteger, - "maxbitrate": isInteger, - "playbackmethod": isArrayOfNums, - "playbackend": func(value interface{}) bool { return isInteger(value) && validPlaybackEnd[toInt(value)] }, - "delivery": isArrayOfNums, - "pos": func(value interface{}) bool { return isInteger(value) && validPos[toInt(value)] }, - "api": isArrayOfNums, -} - -// Helper function to convert interface to int -func toInt(value interface{}) int { - switch v := value.(type) { - case int: - return v - case float64: - return int(v) - case string: - if i, err := strconv.Atoi(v); err == nil { - return i - } - } - return 0 -} - // Builder builds a new insticatorance of the Foo adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { bidder := &adapter{ @@ -201,14 +72,6 @@ func getMediaTypeForBid(bid *openrtb2.Bid) openrtb_ext.BidType { } } -func getBidType(ext bidExt) openrtb_ext.BidType { - if ext.Insticator.MediaType == "video" { - return openrtb_ext.BidTypeVideo - } - - return openrtb_ext.BidTypeBanner -} - func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { var errs []error @@ -224,7 +87,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte for i := 0; i < len(request.Imp); i++ { if impCopy, err := makeImps(request.Imp[i]); err == nil { - var impExt Ext + var impExt ext // Populate site.publisher.id from imp extension only once if request.Site != nil && i == 0 { populatePublisherId(&impCopy, request) @@ -302,21 +165,11 @@ func (a *adapter) makeRequest(request openrtb2.BidRequest, impList []openrtb2.Im } func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if responseData.StatusCode == http.StatusNoContent { + if adapters.IsResponseStatusCodeNoContent(responseData) { return nil, nil } - if responseData.StatusCode == http.StatusBadRequest { - err := &errortypes.BadInput{ - Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), - } - return nil, []error{err} - } - - if responseData.StatusCode != http.StatusOK { - err := &errortypes.BadServerResponse{ - Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), - } + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { return nil, []error{err} } @@ -342,11 +195,6 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R } func makeImps(imp openrtb2.Imp) (openrtb2.Imp, error) { - if imp.Banner == nil && imp.Video == nil { - return openrtb2.Imp{}, &errortypes.BadInput{ - Message: fmt.Sprintf("Imp ID %s must have at least one of [Banner, Video] defined", imp.ID), - } - } var bidderExt adapters.ExtImpBidder if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { @@ -362,7 +210,7 @@ func makeImps(imp openrtb2.Imp) (openrtb2.Imp, error) { } } - var impExt Ext + var impExt ext impExt.Insticator.AdUnitId = insticatorExt.AdUnitId impExt.Insticator.PublisherId = insticatorExt.PublisherId @@ -374,7 +222,6 @@ func makeImps(imp openrtb2.Imp) (openrtb2.Imp, error) { } imp.Ext = impExtJSON - // Validate Video if it exists if imp.Video != nil { videoCopy, err := validateVideoParams(imp.Video) @@ -387,27 +234,8 @@ func makeImps(imp openrtb2.Imp) (openrtb2.Imp, error) { } } } - return imp, nil -} - -func validateVideoParams(video *openrtb2.Video) (*openrtb2.Video, error) { - videoCopy := *video - if (videoCopy.W == nil || *videoCopy.W == 0) || - (videoCopy.H == nil || *videoCopy.H == 0) || - videoCopy.MIMEs == nil { - - return nil, &errortypes.BadInput{ - Message: "One or more invalid or missing video field(s) w, h, mimes", - } - } - - // Validate optional parameters and remove invalid ones - cleanedVideo, err := validateOptionalVideoParams(&videoCopy) - if err != nil { - return nil, err - } - return cleanedVideo, nil + return imp, nil } func makeReqExt(request *openrtb2.BidRequest) ([]byte, error) { @@ -424,10 +252,10 @@ func makeReqExt(request *openrtb2.BidRequest) ([]byte, error) { } if reqExt.Insticator.Caller == nil { - reqExt.Insticator.Caller = make([]InsticatorCaller, 0) + reqExt.Insticator.Caller = make([]insticatorCaller, 0) } - reqExt.Insticator.Caller = append(reqExt.Insticator.Caller, CALLER) + reqExt.Insticator.Caller = append(reqExt.Insticator.Caller, caller) return json.Marshal(reqExt) } @@ -446,65 +274,23 @@ func roundTo4Decimals(amount float64) float64 { return math.Round(amount*10000) / 10000 } -func validateOptionalVideoParams(video *openrtb2.Video) (*openrtb2.Video, error) { - v := reflect.ValueOf(video).Elem() - t := v.Type() - - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - fieldValue := v.Field(i) - - // Convert the field name to camelCase for matching in optionalVideoParams map - jsonTag := field.Tag.Get("json") - if jsonTag == "" { - jsonTag = toCamelCase(field.Name) - } - - // Skip fields that are not in optionalVideoParams - validator, exists := optionalVideoParams[jsonTag] - if !exists { - continue - } - - // Check if the field value is zero/nil and skip if true - if isZeroOrNil(fieldValue) { - continue - } +func validateVideoParams(video *openrtb2.Video) (*openrtb2.Video, error) { + videoCopy := *video + if (videoCopy.W == nil || *videoCopy.W == 0) || + (videoCopy.H == nil || *videoCopy.H == 0) || + videoCopy.MIMEs == nil { - // Validate the field value - if !validator(fieldValue.Interface()) { - // If invalid, set the field to zero value - fieldValue.Set(reflect.Zero(fieldValue.Type())) + return nil, &errortypes.BadInput{ + Message: "One or more invalid or missing video field(s) w, h, mimes", } } - return video, nil -} -// Helper function to convert field name to camelCase -func toCamelCase(s string) string { - if s == "" { - return s - } - return strings.ToLower(string(s[0])) + s[1:] -} - -// Helper function to check if a value is zero or nil -func isZeroOrNil(value reflect.Value) bool { - switch value.Kind() { - case reflect.Ptr, reflect.Interface: - return value.IsNil() - case reflect.Slice, reflect.Array: - return value.Len() == 0 - case reflect.Map: - return len(value.MapKeys()) == 0 - default: - return value.IsZero() - } + return &videoCopy, nil } // populate publisherId to site/app object from imp extension func populatePublisherId(imp *openrtb2.Imp, request *openrtb2.BidRequest) { - var ext Ext + var ext ext if request.Site != nil && request.Site.Publisher == nil { request.Site.Publisher = &openrtb2.Publisher{} diff --git a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json index 6f6cc5e3545..81ec46e84d5 100644 --- a/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json +++ b/adapters/insticator/insticatortest/supplemental/multi-imp-mixed-validation.json @@ -13,15 +13,6 @@ "publisherId": "test-publisher-id" } } - }, - { - "id": "test-imp-id2", - "ext": { - "bidder": { - "adUnitId": "fake-site-id", - "publisherId": "test-publisher-id" - } - } } ], "site": { @@ -98,12 +89,6 @@ } } ], - "expectedMakeRequestsErrors": [ - { - "value": "Imp ID test-imp-id2 must have at least one of [Banner, Video] defined", - "comparison": "literal" - } - ], "expectedBidResponses": [ { "currency": "USD", diff --git a/adapters/insticator/insticatortest/supplemental/status-not-ok.json b/adapters/insticator/insticatortest/supplemental/status-not-ok.json index 814e2eeff2c..e2778985e11 100644 --- a/adapters/insticator/insticatortest/supplemental/status-not-ok.json +++ b/adapters/insticator/insticatortest/supplemental/status-not-ok.json @@ -78,7 +78,7 @@ "expectedMakeBidsErrors": [ { - "value": "Unexpected status code: 400. Run with request.debug = 1 for more info.", + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", "comparison": "literal" } ] From 1f439784433840b069a24f0c4695a4f22819f6fb Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Mon, 12 Aug 2024 19:35:16 +0530 Subject: [PATCH 07/10] refactor error checks --- adapters/insticator/insticator.go | 60 ++++++++++++++++--------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index b8f79cf6e09..79f1c9d1ae6 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -86,36 +86,38 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte request.Ext = reqExt for i := 0; i < len(request.Imp); i++ { - if impCopy, err := makeImps(request.Imp[i]); err == nil { - var impExt ext - // Populate site.publisher.id from imp extension only once - if request.Site != nil && i == 0 { - populatePublisherId(&impCopy, request) - } else if request.App != nil && i == 0 { - populatePublisherId(&impCopy, request) - } + impCopy, err := makeImps(request.Imp[i]) + if err != nil { + errs = append(errs, err) + continue + } - // group together the imp hacing insticator adUnitId. However let's not block request creation. - if err := json.Unmarshal(impCopy.Ext, &impExt); err == nil { - impKey := impExt.Insticator.AdUnitId - - resolvedBidFloor, errFloor := resolveBidFloor(impCopy.BidFloor, impCopy.BidFloorCur, requestInfo) - if errFloor != nil { - errs = append(errs, errFloor) - } else { - if resolvedBidFloor > 0 { - impCopy.BidFloor = resolvedBidFloor - impCopy.BidFloorCur = "USD" - } - } - - groupedImps[impKey] = append(groupedImps[impKey], impCopy) - } else { - errs = append(errs, err) - } - } else { + var impExt ext + + // Populate site.publisher.id from imp extension + if request.Site != nil || request.App != nil { + populatePublisherId(&impCopy, request) + } + + // Group together the imps having Insticator adUnitId. However, let's not block request creation. + if err := json.Unmarshal(impCopy.Ext, &impExt); err != nil { errs = append(errs, err) + continue + } + + impKey := impExt.Insticator.AdUnitId + + resolvedBidFloor, errFloor := resolveBidFloor(impCopy.BidFloor, impCopy.BidFloorCur, requestInfo) + if errFloor != nil { + errs = append(errs, errFloor) + } else { + if resolvedBidFloor > 0 { + impCopy.BidFloor = resolvedBidFloor + impCopy.BidFloorCur = "USD" + } } + + groupedImps[impKey] = append(groupedImps[impKey], impCopy) } for _, impList := range groupedImps { @@ -179,7 +181,9 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R } bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) - bidResponse.Currency = response.Cur + if response.Cur != "" { + bidResponse.Currency = response.Cur + } for _, seatBid := range response.SeatBid { for i := range seatBid.Bid { bid := &seatBid.Bid[i] From c5b5e247c3e832b4b4e6de50a4de19937ff30f62 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Thu, 3 Oct 2024 16:09:16 +0530 Subject: [PATCH 08/10] fix email typo --- static/bidder-info/insticator.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/insticator.yaml b/static/bidder-info/insticator.yaml index 2f93324f6de..240345cb06d 100644 --- a/static/bidder-info/insticator.yaml +++ b/static/bidder-info/insticator.yaml @@ -1,6 +1,6 @@ endpoint: "https://ex.ingage.tech/v1/prebidserver" maintainer: - email: "predid@insticator.com" + email: "prebid@insticator.com" gvlVendorID: 910 capabilities: app: From 4dfb854347ad6570c98bb2c48c3e7a30fad943c2 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Wed, 30 Oct 2024 01:06:44 +0530 Subject: [PATCH 09/10] add invalidparams for insticator --- adapters/insticator/params_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/adapters/insticator/params_test.go b/adapters/insticator/params_test.go index ba4465ea4a3..fd8682a2f03 100644 --- a/adapters/insticator/params_test.go +++ b/adapters/insticator/params_test.go @@ -46,6 +46,12 @@ var validParams = []string{ } var invalidParams = []string{ - `{"publisherId": "inview"}`, - `{"publisherId": 123, "adUnitId": "fakesiteid2"}`, + `{"publisherId": "inview"}`, // Missing adUnitId + `{"publisherId": 123, "adUnitId": "fakesiteid2"}`, // publisherId should be a string + `{"adUnitId": "fakesiteid3"}`, // Missing publisherId + `{"publisherId": "inview", "adUnitId": 456}`, // adUnitId should be a string + `{"publisherId": null, "adUnitId": "fakesiteid5"}`, // Null publisherId + `{"publisherId": "inview", "adUnitId": null}`, // Null adUnitId + `{"publisherId": true, "adUnitId": "fakesiteid6"}`, // publisherId should be a string, got boolean + `{"publisherId": "inview", "adUnitId": [1, 2, 3]}`, // adUnitId should be a string, got array } From c776f19d11b9e7535f0b4bba01303de6421b08f5 Mon Sep 17 00:00:00 2001 From: shubhamc-ins Date: Mon, 4 Nov 2024 22:07:54 +0530 Subject: [PATCH 10/10] update imports to v3 for insticator --- adapters/insticator/insticator.go | 8 ++++---- adapters/insticator/insticator_test.go | 6 +++--- adapters/insticator/params_test.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/adapters/insticator/insticator.go b/adapters/insticator/insticator.go index 79f1c9d1ae6..e659c21d31c 100644 --- a/adapters/insticator/insticator.go +++ b/adapters/insticator/insticator.go @@ -8,10 +8,10 @@ import ( "strings" "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v2/adapters" - "github.com/prebid/prebid-server/v2/config" - "github.com/prebid/prebid-server/v2/errortypes" - "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" ) type ext struct { diff --git a/adapters/insticator/insticator_test.go b/adapters/insticator/insticator_test.go index e929402b822..b34595177b5 100644 --- a/adapters/insticator/insticator_test.go +++ b/adapters/insticator/insticator_test.go @@ -3,9 +3,9 @@ package insticator import ( "testing" - "github.com/prebid/prebid-server/v2/adapters/adapterstest" - "github.com/prebid/prebid-server/v2/config" - "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" ) func TestJsonSamples(t *testing.T) { diff --git a/adapters/insticator/params_test.go b/adapters/insticator/params_test.go index fd8682a2f03..47d2bdf44fc 100644 --- a/adapters/insticator/params_test.go +++ b/adapters/insticator/params_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/prebid/prebid-server/v3/openrtb_ext" ) // This file actually intends to test static/bidder-params/Insticator.json