Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TPMN Bidder Adapter: write id in first party domain; force syncs with various parties #8341

Merged
merged 8 commits into from
May 10, 2022
78 changes: 61 additions & 17 deletions modules/tpmnBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
/* eslint-disable no-tabs */
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { parseUrl, deepAccess } from '../src/utils.js';
import { getStorageManager } from '../src/storageManager.js';
import { BANNER } from '../src/mediaTypes.js';
import { config } from '../src/config.js';

export const ADAPTER_VERSION = '1';
const SUPPORTED_AD_TYPES = [BANNER];

const BIDDER_CODE = 'tpmn';
const URL = 'https://ad.tpmn.co.kr/prebidhb.tpmn';
const IFRAMESYNC = 'https://ad.tpmn.co.kr/sync.tpmn?type=iframe';
export const storage = getStorageManager({bidderCode: BIDDER_CODE});

export const spec = {
code: BIDDER_CODE,
Expand All @@ -18,20 +21,20 @@ export const spec = {
* @param {object} bid The bid to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function(bid) {
isBidRequestValid: function (bid) {
return 'params' in bid &&
'inventoryId' in bid.params &&
'publisherId' in bid.params &&
!isNaN(Number(bid.params.inventoryId)) &&
bid.params.inventoryId > 0 &&
(typeof bid.mediaTypes.banner.sizes != 'undefined'); // only accepting appropriate sizes
'inventoryId' in bid.params &&
'publisherId' in bid.params &&
!isNaN(Number(bid.params.inventoryId)) &&
bid.params.inventoryId > 0 &&
(typeof bid.mediaTypes.banner.sizes != 'undefined'); // only accepting appropriate sizes
},

/**
* @param {BidRequest[]} bidRequests
* @param {*} bidderRequest
* @return {ServerRequest}
*/
* @param {BidRequest[]} bidRequests
* @param {*} bidderRequest
* @return {ServerRequest}
*/
buildRequests: (bidRequests, bidderRequest) => {
if (bidRequests.length === 0) {
return [];
Expand All @@ -49,11 +52,11 @@ export const spec = {
}];
},
/**
* Unpack the response from the server into a list of bids.
*
* @param {serverResponse} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
* Unpack the response from the server into a list of bids.
*
* @param {serverResponse} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function (serverResponse, serverRequest) {
if (!Array.isArray(serverResponse.body)) {
return [];
Expand All @@ -63,7 +66,48 @@ export const spec = {
// our server directly returns the format needed by prebid.js so no more
// transformation is needed here.
return bidResults;
}
},

getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) {
const syncArr = [];
if (syncOptions.iframeEnabled) {
let policyParam = '';
if (gdprConsent && gdprConsent.consentString) {
if (typeof gdprConsent.gdprApplies === 'boolean') {
policyParam += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
} else {
policyParam += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`;
}
}
if (uspConsent && uspConsent.consentString) {
policyParam += `&ccpa_consent=${uspConsent.consentString}`;
}
const coppa = config.getConfig('coppa') ? 1 : 0;
policyParam += `&coppa=${coppa}`;
syncArr.push({
type: 'iframe',
url: IFRAMESYNC + policyParam
})
} else {
syncArr.push({
type: 'image',
url: 'https://x.bidswitch.net/sync?ssp=tpmn'
});
syncArr.push({
type: 'image',
url: 'https://gocm.c.appier.net/tpmn'
});
syncArr.push({
type: 'image',
url: 'https://info.mmnneo.com/getGuidRedirect.info?url=https%3A%2F%2Fad.tpmn.co.kr%2Fcookiesync.tpmn%3Ftpmn_nid%3Dbf91e8b3b9d3f1af3fc1d657f090b4fb%26tpmn_buid%3D'
});
syncArr.push({
type: 'image',
url: 'https://sync.aralego.com/idSync?redirect=https%3A%2F%2Fad.tpmn.co.kr%2FpixelCt.tpmn%3Ftpmn_nid%3Dde91e8b3b9d3f1af3fc1d657f090b815%26tpmn_buid%3DSspCookieUserId'
});
}
return syncArr;
},
};

registerBidder(spec);
Expand Down
103 changes: 84 additions & 19 deletions test/spec/modules/tpmnBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
/* eslint-disable no-tabs */
import { expect } from 'chai';
import { spec } from 'modules/tpmnBidAdapter.js';
import {expect} from 'chai';
import {spec, storage} from 'modules/tpmnBidAdapter.js';
import {generateUUID} from '../../../src/utils.js';
import {newBidder} from '../../../src/adapters/bidderFactory';
import * as sinon from 'sinon';

describe('tpmnAdapterTests', function() {
describe('isBidRequestValid', function() {
describe('tpmnAdapterTests', function () {
const adapter = newBidder(spec);
const BIDDER_CODE = 'tpmn';
let sandbox = sinon.sandbox.create();
let getCookieStub;

beforeEach(function () {
$$PREBID_GLOBAL$$.bidderSettings = {
tpmn: {
storageAllowed: true
}
};
sandbox = sinon.sandbox.create();
getCookieStub = sinon.stub(storage, 'getCookie');
});

afterEach(function () {
sandbox.restore();
getCookieStub.restore();
$$PREBID_GLOBAL$$.bidderSettings = {};
});

describe('inherited functions', function () {
it('exists and is a function', function () {
expect(adapter.callBids).to.exist.and.to.be.a('function')
})
});

describe('isBidRequestValid', function () {
let bid = {
adUnitCode: 'temp-unitcode',
bidder: 'tpmn',
Expand All @@ -20,17 +50,18 @@ describe('tpmnAdapterTests', function() {
}
}
};
it('should return true if a bid is valid banner bid request', function() {

it('should return true if a bid is valid banner bid request', function () {
expect(spec.isBidRequestValid(bid)).to.be.equal(true);
});

it('should return false where requried param is missing', function() {
it('should return false where requried param is missing', function () {
let bid = Object.assign({}, bid);
bid.params = {};
expect(spec.isBidRequestValid(bid)).to.be.equal(false);
});

it('should return false when required param values have invalid type', function() {
it('should return false when required param values have invalid type', function () {
let bid = Object.assign({}, bid);
bid.params = {
'inventoryId': null,
Expand All @@ -40,14 +71,14 @@ describe('tpmnAdapterTests', function() {
});
});

describe('buildRequests', function() {
it('should return an empty list if there are no bid requests', function() {
describe('buildRequests', function () {
it('should return an empty list if there are no bid requests', function () {
const emptyBidRequests = [];
const bidderRequest = {};
const request = spec.buildRequests(emptyBidRequests, bidderRequest);
expect(request).to.be.an('array').that.is.empty;
});
it('should generate a POST server request with bidder API url, data', function() {
it('should generate a POST server request with bidder API url, data', function () {
const bid = {
adUnitCode: 'temp-unitcode',
bidder: 'tpmn',
Expand All @@ -65,13 +96,15 @@ describe('tpmnAdapterTests', function() {
}
};
const tempBidRequests = [bid];
const tempBidderRequest = {refererInfo: {
referer: 'http://localhost/test',
site: {
domain: 'localhost',
page: 'http://localhost/test'
const tempBidderRequest = {
refererInfo: {
referer: 'http://localhost/test',
site: {
domain: 'localhost',
page: 'http://localhost/test'
}
}
}};
};
const builtRequest = spec.buildRequests(tempBidRequests, tempBidderRequest);

expect(builtRequest).to.have.lengthOf(1);
Expand All @@ -96,7 +129,7 @@ describe('tpmnAdapterTests', function() {
});
});

describe('interpretResponse', function() {
describe('interpretResponse', function () {
const bid = {
adUnitCode: 'temp-unitcode',
bidder: 'tpmn',
Expand All @@ -115,12 +148,12 @@ describe('tpmnAdapterTests', function() {
};
const tempBidRequests = [bid];

it('should return an empty aray to indicate no valid bids', function() {
it('should return an empty aray to indicate no valid bids', function () {
const emptyServerResponse = {};
const bidResponses = spec.interpretResponse(emptyServerResponse, tempBidRequests);
expect(bidResponses).is.an('array').that.is.empty;
});
it('should return an empty array to indicate no valid bids', function() {
it('should return an empty array to indicate no valid bids', function () {
const mockBidResult = {
requestId: '9cf19229-34f6-4d06-bc1d-0e44e8d616c8',
cpm: 10.0,
Expand All @@ -141,4 +174,36 @@ describe('tpmnAdapterTests', function() {
expect(bidResponses).deep.equal([mockBidResult]);
});
});

describe('getUserSync', function () {
const KEY_ID = 'uuid';
const TMP_UUID = generateUUID().replace(/-/g, '');

it('getCookie mock Test', () => {
const uuid = storage.getCookie(KEY_ID);
expect(uuid).to.equal(undefined);
});

it('getCookie mock Test', () => {
expect(TMP_UUID.length).to.equal(32);
getCookieStub.withArgs(KEY_ID).returns(TMP_UUID);
const uuid = storage.getCookie(KEY_ID);
expect(uuid).to.equal(TMP_UUID);
});

it('case 1 -> allow iframe', () => {
const syncs = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true});
expect(syncs.length).to.equal(1);
expect(syncs[0].type).to.equal('iframe');
});

it('case 2 -> allow pixel with static sync', () => {
const syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true });
expect(syncs.length).to.be.equal(4);
expect(syncs[0].type).to.be.equal('image');
expect(syncs[1].type).to.be.equal('image');
expect(syncs[2].type).to.be.equal('image');
expect(syncs[3].type).to.be.equal('image');
});
});
});