From 9a8719e6772391a22e32800f4317370c778237c3 Mon Sep 17 00:00:00 2001 From: Serhii Kozlov Date: Thu, 15 Apr 2021 17:58:01 +0300 Subject: [PATCH 1/4] Shinze adapter version 1.0.0 --- modules/shinezBidAdapter.js | 80 +++++++++ modules/shinezBidAdapter.md | 33 ++++ test/spec/modules/shinezBidAdapter_spec.js | 183 +++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100644 modules/shinezBidAdapter.js create mode 100644 modules/shinezBidAdapter.md create mode 100644 test/spec/modules/shinezBidAdapter_spec.js diff --git a/modules/shinezBidAdapter.js b/modules/shinezBidAdapter.js new file mode 100644 index 00000000000..384c3069ac8 --- /dev/null +++ b/modules/shinezBidAdapter.js @@ -0,0 +1,80 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'shinez'; +const BIDDER_SHORT_CODE = 'shz'; +const ADAPTER_VERSION = '1.0.0'; + +const TARGET_URL = 'https://shinez-ssp.shinez.workers.dev/prebid'; + +export const spec = { + code: BIDDER_CODE, + version: ADAPTER_VERSION, + aliases: { + code: BIDDER_SHORT_CODE + }, + supportedMediaTypes: [ BANNER ], + isBidRequestValid: isBidRequestValid, + buildRequests: buildRequests, + interpretResponse: interpretResponse, +}; + +export const internal = { + _buildServerBidRequest, + _convertServerBidResponse, + TARGET_URL +} + +function isBidRequestValid(bid) { + return !!(bid && bid.params && + bid.params.placementId && typeof bid.params.placementId === 'string' && + (bid.params.unit == null || (typeof bid.params.unit === 'string' && bid.params.unit.length > 0)) + ); +} + +function buildRequests(validBidRequests, bidderRequest) { + const utcOffset = (new Date()).getTimezoneOffset(); + const data = validBidRequests + .map(bidRequest => internal._buildServerBidRequest(bidRequest, bidderRequest, utcOffset)); + const request = { + method: 'POST', + url: new URL(TARGET_URL), + data: data + }; + return request; +} + +function interpretResponse(serverResponse, request) { + return serverResponse.body.map(internal._convertServerBidResponse); +} + +function _buildServerBidRequest(bidRequest, bidderRequest, utcOffset) { + return { + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + crumbs: bidRequest.crumbs, + fpd: bidRequest.fpd, + mediaTypes: bidRequest.mediaTypes, + refererInfo: bidderRequest.refererInfo, + placementId: bidRequest.params.placementId, + utcOffset: utcOffset, + adUnitCode: bidRequest.adUnitCode, + unit: bidRequest.params.unit + } +} + +function _convertServerBidResponse(response) { + return { + requestId: response.bidId, + cpm: response.cpm, + currency: response.currency, + width: response.width, + height: response.height, + ad: response.ad, + ttl: response.ttl, + creativeId: response.creativeId, + netRevenue: response.netRevenue + }; +} + +registerBidder(spec); diff --git a/modules/shinezBidAdapter.md b/modules/shinezBidAdapter.md new file mode 100644 index 00000000000..e040cfbf36b --- /dev/null +++ b/modules/shinezBidAdapter.md @@ -0,0 +1,33 @@ +# Overview + +``` +Module Name: Shinez Bidder Adapter +Module Type: Bidder Adapter +Maintainer: tech-team@shinez.io +``` + +# Description + +Connects to shinez.io demand sources. + +The Shinez adapter requires setup and approval from the Shinez team. +Please reach out to tech-team@shinez.io for more information. + +# Test Parameters + +```javascript +var adUnits = [{ + code: "test-div", + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: "shinez", + params: { + placementId: "00654321" + } + }] +}]; +``` \ No newline at end of file diff --git a/test/spec/modules/shinezBidAdapter_spec.js b/test/spec/modules/shinezBidAdapter_spec.js new file mode 100644 index 00000000000..65fd417e8d3 --- /dev/null +++ b/test/spec/modules/shinezBidAdapter_spec.js @@ -0,0 +1,183 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { spec, internal } from 'modules/shinezBidAdapter.js'; + +describe('shinezBidAdapter', () => { + let sandbox; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + afterEach(() => { + sandbox.restore(); + }) + describe('isBidRequestValid', () => { + const cases = [ + [ + 'should return false when placementId is missing', + { + params: {}, + }, + false, + ], + [ + 'should return false when placementId has wrong type', + { + params: { + placementId: 123, + }, + }, + false, + ], + [ + 'should return false when unit has wrong type', + { + params: { + placementId: '00654321', + unit: 150, + }, + }, + false, + ], + [ + 'should return true when required params found and valid', + { + params: { + placementId: '00654321', + }, + }, + true, + ], + [ + 'should return true when all params found and valid', + { + params: { + placementId: '00654321', + unit: '__header-bid-1', + }, + }, + true, + ], + ]; + cases.map(([description, request, expected]) => { + it(description, () => { + const result = spec.isBidRequestValid(request); + expect(result).to.be.equal(expected); + }); + }); + }); + describe('buildRequests', () => { + it('should build server request correctly', () => { + const utcOffset = 300; + const validBidRequests = [ { bidId: '1' }, { bidId: '2' } ]; + const bidderRequest = { refererInfo: { referer: 'http://site-with-ads.com' } }; + sandbox.stub(Date.prototype, 'getTimezoneOffset').returns(utcOffset); + sandbox.stub(internal, '_buildServerBidRequest') + .callsFake((bidRequest, bidderRequest, utcOffset) => ({ + bidId: bidRequest.bidId, + refererInfo: bidderRequest.refererInfo, + utcOffset: utcOffset }) + ); + const payload = [ + { + bidId: '1', + refererInfo: bidderRequest.refererInfo, + utcOffset: utcOffset + }, + { + bidId: '2', + refererInfo: bidderRequest.refererInfo, + utcOffset: utcOffset + } + ] + const result = spec.buildRequests(validBidRequests, bidderRequest); + expect(result.method, 'request should be POST\'ed').equal('POST'); + expect(result.url.toString(), 'request should be send to correct url').equal(internal.TARGET_URL); + expect(result.data, 'request should have correct payload').to.deep.equal(payload); + }); + }); + describe('interpretResponse', () => { + it('should interpret bid responses correctly', () => { + sandbox + .stub(internal, '_convertServerBidResponse') + .callsFake((request) => ({ requestId: request.bidId })); + const responses = { body: [{ bidId: '1' }, { bidId: '2' }] }; + const expected = [{ requestId: '1' }, { requestId: '2' }]; + const result = spec.interpretResponse(responses); + expect(result).to.deep.equal(expected); + }); + }); + describe('_buildServerBidRequest', () => { + it('should build server bid request correctly', () => { + const bidRequest = { + bidId: '22cee66f4fcb0a', + transactionId: '44b6190e-9085-49bd-a6b9-b603544e4bfe', + crumbs: { + pubcid: 'c8584a82-bec3-4347-8d3e-e7612438a161', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + params: { + placementId: '00654321', + unit: '__header-bid-1', + }, + adUnitCode: '/19968336/header-bid-tag-1', + }; + const bidderRequest = { + fpd: { + ortb2: { + site: 'http://site-with-ads.com', + }, + }, + refererInfo: { + referer: 'http://site-with-ads.com', + }, + }; + const utcOffset = 300; + const expected = { + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + crumbs: bidRequest.crumbs, + fpd: bidRequest.fpd, + mediaTypes: bidRequest.mediaTypes, + refererInfo: bidderRequest.refererInfo, + placementId: bidRequest.params.placementId, + utcOffset: utcOffset, + adUnitCode: bidRequest.adUnitCode, + unit: bidRequest.params.unit + }; + const result = internal._buildServerBidRequest(bidRequest, bidderRequest, utcOffset); + expect(result).to.deep.equal(expected); + }); + }); + describe('_convertServerBidResponse', () => { + it('should convert server response bid correctly', () => { + const response = { + bidId: '2ece6496f4d0c9', + cpm: 1, + currency: 'USD', + width: 300, + height: 250, + ad: `

The Ad

`, + ttl: 60, + creativeId: 'V8qlA6guwm', + netRevenue: true, + }; + const expected = { + requestId: response.bidId, + cpm: response.cpm, + currency: response.currency, + width: response.width, + height: response.height, + ad: response.ad, + ttl: response.ttl, + creativeId: response.creativeId, + netRevenue: response.netRevenue, + }; + const result = internal._convertServerBidResponse(response); + expect(result).to.deep.equal(expected); + }); + }); +}); From b4f1166bdb39c3544f86b10310a249e3cac942db Mon Sep 17 00:00:00 2001 From: Serhii Kozlov Date: Mon, 19 Apr 2021 11:56:40 +0300 Subject: [PATCH 2/4] map for arrays replaced with forEach, fpd temporarily removed --- modules/shinezBidAdapter.js | 17 +++++++++++------ test/spec/modules/shinezBidAdapter_spec.js | 14 ++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/modules/shinezBidAdapter.js b/modules/shinezBidAdapter.js index 384c3069ac8..870496591ce 100644 --- a/modules/shinezBidAdapter.js +++ b/modules/shinezBidAdapter.js @@ -21,7 +21,7 @@ export const spec = { export const internal = { _buildServerBidRequest, - _convertServerBidResponse, + _convertServerBid, TARGET_URL } @@ -34,8 +34,10 @@ function isBidRequestValid(bid) { function buildRequests(validBidRequests, bidderRequest) { const utcOffset = (new Date()).getTimezoneOffset(); - const data = validBidRequests - .map(bidRequest => internal._buildServerBidRequest(bidRequest, bidderRequest, utcOffset)); + const data = []; + validBidRequests.forEach(function(bidRequest) { + data.push(internal._buildServerBidRequest(bidRequest, bidderRequest, utcOffset)); + }); const request = { method: 'POST', url: new URL(TARGET_URL), @@ -45,7 +47,11 @@ function buildRequests(validBidRequests, bidderRequest) { } function interpretResponse(serverResponse, request) { - return serverResponse.body.map(internal._convertServerBidResponse); + const bids = []; + serverResponse.body.forEach(function(serverBid) { + bids.push(internal._convertServerBid(serverBid)); + }); + return bids; } function _buildServerBidRequest(bidRequest, bidderRequest, utcOffset) { @@ -53,7 +59,6 @@ function _buildServerBidRequest(bidRequest, bidderRequest, utcOffset) { bidId: bidRequest.bidId, transactionId: bidRequest.transactionId, crumbs: bidRequest.crumbs, - fpd: bidRequest.fpd, mediaTypes: bidRequest.mediaTypes, refererInfo: bidderRequest.refererInfo, placementId: bidRequest.params.placementId, @@ -63,7 +68,7 @@ function _buildServerBidRequest(bidRequest, bidderRequest, utcOffset) { } } -function _convertServerBidResponse(response) { +function _convertServerBid(response) { return { requestId: response.bidId, cpm: response.cpm, diff --git a/test/spec/modules/shinezBidAdapter_spec.js b/test/spec/modules/shinezBidAdapter_spec.js index 65fd417e8d3..587476ecd4f 100644 --- a/test/spec/modules/shinezBidAdapter_spec.js +++ b/test/spec/modules/shinezBidAdapter_spec.js @@ -98,7 +98,7 @@ describe('shinezBidAdapter', () => { describe('interpretResponse', () => { it('should interpret bid responses correctly', () => { sandbox - .stub(internal, '_convertServerBidResponse') + .stub(internal, '_convertServerBid') .callsFake((request) => ({ requestId: request.bidId })); const responses = { body: [{ bidId: '1' }, { bidId: '2' }] }; const expected = [{ requestId: '1' }, { requestId: '2' }]; @@ -126,11 +126,6 @@ describe('shinezBidAdapter', () => { adUnitCode: '/19968336/header-bid-tag-1', }; const bidderRequest = { - fpd: { - ortb2: { - site: 'http://site-with-ads.com', - }, - }, refererInfo: { referer: 'http://site-with-ads.com', }, @@ -140,7 +135,6 @@ describe('shinezBidAdapter', () => { bidId: bidRequest.bidId, transactionId: bidRequest.transactionId, crumbs: bidRequest.crumbs, - fpd: bidRequest.fpd, mediaTypes: bidRequest.mediaTypes, refererInfo: bidderRequest.refererInfo, placementId: bidRequest.params.placementId, @@ -152,8 +146,8 @@ describe('shinezBidAdapter', () => { expect(result).to.deep.equal(expected); }); }); - describe('_convertServerBidResponse', () => { - it('should convert server response bid correctly', () => { + describe('_convertServerBid', () => { + it('should convert server bid correctly', () => { const response = { bidId: '2ece6496f4d0c9', cpm: 1, @@ -176,7 +170,7 @@ describe('shinezBidAdapter', () => { creativeId: response.creativeId, netRevenue: response.netRevenue, }; - const result = internal._convertServerBidResponse(response); + const result = internal._convertServerBid(response); expect(result).to.deep.equal(expected); }); }); From 7ae2fe816881f60754f8eaba19ff32f21bb55159 Mon Sep 17 00:00:00 2001 From: Serhii Kozlov Date: Mon, 19 Apr 2021 12:36:14 +0300 Subject: [PATCH 3/4] switched to only public interface testing --- modules/shinezBidAdapter.js | 6 +- test/spec/modules/shinezBidAdapter_spec.js | 162 +++++++++------------ 2 files changed, 71 insertions(+), 97 deletions(-) diff --git a/modules/shinezBidAdapter.js b/modules/shinezBidAdapter.js index 870496591ce..35ce21e5ae3 100644 --- a/modules/shinezBidAdapter.js +++ b/modules/shinezBidAdapter.js @@ -20,8 +20,6 @@ export const spec = { }; export const internal = { - _buildServerBidRequest, - _convertServerBid, TARGET_URL } @@ -36,7 +34,7 @@ function buildRequests(validBidRequests, bidderRequest) { const utcOffset = (new Date()).getTimezoneOffset(); const data = []; validBidRequests.forEach(function(bidRequest) { - data.push(internal._buildServerBidRequest(bidRequest, bidderRequest, utcOffset)); + data.push(_buildServerBidRequest(bidRequest, bidderRequest, utcOffset)); }); const request = { method: 'POST', @@ -49,7 +47,7 @@ function buildRequests(validBidRequests, bidderRequest) { function interpretResponse(serverResponse, request) { const bids = []; serverResponse.body.forEach(function(serverBid) { - bids.push(internal._convertServerBid(serverBid)); + bids.push(_convertServerBid(serverBid)); }); return bids; } diff --git a/test/spec/modules/shinezBidAdapter_spec.js b/test/spec/modules/shinezBidAdapter_spec.js index 587476ecd4f..0502833dc68 100644 --- a/test/spec/modules/shinezBidAdapter_spec.js +++ b/test/spec/modules/shinezBidAdapter_spec.js @@ -9,7 +9,7 @@ describe('shinezBidAdapter', () => { }); afterEach(() => { sandbox.restore(); - }) + }); describe('isBidRequestValid', () => { const cases = [ [ @@ -68,110 +68,86 @@ describe('shinezBidAdapter', () => { describe('buildRequests', () => { it('should build server request correctly', () => { const utcOffset = 300; - const validBidRequests = [ { bidId: '1' }, { bidId: '2' } ]; - const bidderRequest = { refererInfo: { referer: 'http://site-with-ads.com' } }; - sandbox.stub(Date.prototype, 'getTimezoneOffset').returns(utcOffset); - sandbox.stub(internal, '_buildServerBidRequest') - .callsFake((bidRequest, bidderRequest, utcOffset) => ({ - bidId: bidRequest.bidId, - refererInfo: bidderRequest.refererInfo, - utcOffset: utcOffset }) - ); - const payload = [ + const validBidRequests = [ { - bidId: '1', - refererInfo: bidderRequest.refererInfo, - utcOffset: utcOffset - }, - { - bidId: '2', - refererInfo: bidderRequest.refererInfo, - utcOffset: utcOffset - } - ] - const result = spec.buildRequests(validBidRequests, bidderRequest); - expect(result.method, 'request should be POST\'ed').equal('POST'); - expect(result.url.toString(), 'request should be send to correct url').equal(internal.TARGET_URL); - expect(result.data, 'request should have correct payload').to.deep.equal(payload); - }); - }); - describe('interpretResponse', () => { - it('should interpret bid responses correctly', () => { - sandbox - .stub(internal, '_convertServerBid') - .callsFake((request) => ({ requestId: request.bidId })); - const responses = { body: [{ bidId: '1' }, { bidId: '2' }] }; - const expected = [{ requestId: '1' }, { requestId: '2' }]; - const result = spec.interpretResponse(responses); - expect(result).to.deep.equal(expected); - }); - }); - describe('_buildServerBidRequest', () => { - it('should build server bid request correctly', () => { - const bidRequest = { - bidId: '22cee66f4fcb0a', - transactionId: '44b6190e-9085-49bd-a6b9-b603544e4bfe', - crumbs: { - pubcid: 'c8584a82-bec3-4347-8d3e-e7612438a161', - }, - mediaTypes: { - banner: { - sizes: [[300, 250]], + params: { + placementId: '00654321', + unit: 'header-bid-tag-1-shinez', }, + crumbs: { + pubcid: 'c8584a82-bec3-4347-8d3e-e7612438a161', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + adUnitCode: 'header-bid-tag-1', + transactionId: '665760dc-a249-4be7-ae86-91f417b2c65d', }, - params: { - placementId: '00654321', - unit: '__header-bid-1', - }, - adUnitCode: '/19968336/header-bid-tag-1', - }; + ]; const bidderRequest = { refererInfo: { referer: 'http://site-with-ads.com', }, }; - const utcOffset = 300; - const expected = { - bidId: bidRequest.bidId, - transactionId: bidRequest.transactionId, - crumbs: bidRequest.crumbs, - mediaTypes: bidRequest.mediaTypes, - refererInfo: bidderRequest.refererInfo, - placementId: bidRequest.params.placementId, - utcOffset: utcOffset, - adUnitCode: bidRequest.adUnitCode, - unit: bidRequest.params.unit - }; - const result = internal._buildServerBidRequest(bidRequest, bidderRequest, utcOffset); - expect(result).to.deep.equal(expected); + sandbox.stub(Date.prototype, 'getTimezoneOffset').returns(utcOffset); + const result = spec.buildRequests(validBidRequests, bidderRequest); + const expectedData = [ + { + bidId: validBidRequests[0].bidId, + transactionId: validBidRequests[0].transactionId, + crumbs: validBidRequests[0].crumbs, + mediaTypes: validBidRequests[0].mediaTypes, + refererInfo: bidderRequest.refererInfo, + adUnitCode: validBidRequests[0].adUnitCode, + utcOffset: utcOffset, + placementId: validBidRequests[0].params.placementId, + unit: validBidRequests[0].params.unit, + }, + ]; + expect(result.method, "request should be POST'ed").equal('POST'); + expect( + result.url.toString(), + 'request should be send to correct url' + ).equal(internal.TARGET_URL); + expect(result.data, 'request should have correct payload').to.deep.equal( + expectedData + ); }); }); - describe('_convertServerBid', () => { - it('should convert server bid correctly', () => { + describe('interpretResponse', () => { + it('should interpret bid responses correctly', () => { const response = { - bidId: '2ece6496f4d0c9', - cpm: 1, - currency: 'USD', - width: 300, - height: 250, - ad: `

The Ad

`, - ttl: 60, - creativeId: 'V8qlA6guwm', - netRevenue: true, - }; - const expected = { - requestId: response.bidId, - cpm: response.cpm, - currency: response.currency, - width: response.width, - height: response.height, - ad: response.ad, - ttl: response.ttl, - creativeId: response.creativeId, - netRevenue: response.netRevenue, + body: [ + { + bidId: '2ece6496f4d0c9', + cpm: 0.03, + currency: 'USD', + width: 300, + height: 250, + ad: `

The Ad

`, + ttl: 60, + creativeId: 'V8qlA6guwm', + netRevenue: true, + }, + ], }; - const result = internal._convertServerBid(response); - expect(result).to.deep.equal(expected); + const bids = [ + { + requestId: response.body[0].bidId, + cpm: response.body[0].cpm, + currency: response.body[0].currency, + width: response.body[0].width, + height: response.body[0].height, + ad: response.body[0].ad, + ttl: response.body[0].ttl, + creativeId: response.body[0].creativeId, + netRevenue: response.body[0].netRevenue, + }, + ]; + const result = spec.interpretResponse(response); + expect(result).to.deep.equal(bids); }); }); }); From 6043da84d40abded526924f5f80acfcc6d44ce5f Mon Sep 17 00:00:00 2001 From: Serhii Kozlov Date: Mon, 19 Apr 2021 13:15:34 +0300 Subject: [PATCH 4/4] Usage of URL removed --- modules/shinezBidAdapter.js | 2 +- test/spec/modules/shinezBidAdapter_spec.js | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/shinezBidAdapter.js b/modules/shinezBidAdapter.js index 35ce21e5ae3..d5734d23fdc 100644 --- a/modules/shinezBidAdapter.js +++ b/modules/shinezBidAdapter.js @@ -38,7 +38,7 @@ function buildRequests(validBidRequests, bidderRequest) { }); const request = { method: 'POST', - url: new URL(TARGET_URL), + url: TARGET_URL, data: data }; return request; diff --git a/test/spec/modules/shinezBidAdapter_spec.js b/test/spec/modules/shinezBidAdapter_spec.js index 0502833dc68..cc3c2451c5d 100644 --- a/test/spec/modules/shinezBidAdapter_spec.js +++ b/test/spec/modules/shinezBidAdapter_spec.js @@ -107,10 +107,9 @@ describe('shinezBidAdapter', () => { }, ]; expect(result.method, "request should be POST'ed").equal('POST'); - expect( - result.url.toString(), - 'request should be send to correct url' - ).equal(internal.TARGET_URL); + expect(result.url, 'request should be send to correct url').equal( + internal.TARGET_URL + ); expect(result.data, 'request should have correct payload').to.deep.equal( expectedData );