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

add user syncing for kargo #3099

Merged
merged 1 commit into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions modules/kargoBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {config} from 'src/config';
import {registerBidder} from 'src/adapters/bidderFactory';
const BIDDER_CODE = 'kargo';
const HOST = 'https://krk.kargo.com';
const SYNC = 'https://crb.kargo.com/api/v1/initsyncrnd/{UUID}?seed={SEED}&idx={INDEX}';
const SYNC_COUNT = 5;
export const spec = {
code: BIDDER_CODE,
isBidRequestValid: function(bid) {
Expand Down Expand Up @@ -54,6 +56,20 @@ export const spec = {
}
return bidResponses;
},
getUserSyncs: function(syncOptions) {
const syncs = [];
const seed = spec._generateRandomUuid();
const clientId = spec._getClientId();
if (syncOptions.iframeEnabled && seed && clientId) {
for (let i = 0; i < SYNC_COUNT; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm the intended logic here - this setup will always generate 5 sync requests that are largely the same minus the idx param which gets incremented by 1 for each subsequent sync request. Is that the expected behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we want to attempt 5 syncs (barring a cap set by the configuration) and we want our server to be able to choose what to sync, potentially randomly, using a stateless system that gets passed an instance ID/seed and an incrementer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying.

syncs.push({
type: 'iframe',
url: SYNC.replace('{UUID}', clientId).replace('{SEED}', seed).replace('{INDEX}', i)
});
}
}
return syncs;
},

// PRIVATE
_readCookie(name) {
Expand Down Expand Up @@ -150,13 +166,34 @@ export const spec = {
};
},

_getClientId() {
const uid = spec._getUid();
return uid.clientId;
},

_getAllMetadata() {
return {
userIDs: spec._getUserIds(),
krux: spec._getKrux(),
pageURL: window.location.href,
rawCRB: spec._readCookie('krg_crb')
};
},

_generateRandomUuid() {
try {
// crypto.getRandomValues is supported everywhere but Opera Mini for years
var buffer = new Uint8Array(16);
crypto.getRandomValues(buffer);
buffer[6] = (buffer[6] & ~176) | 64;
buffer[8] = (buffer[8] & ~64) | 128;
var hex = Array.prototype.map.call(new Uint8Array(buffer), function(x) {
return ('00' + x.toString(16)).slice(-2);
}).join('');
return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20);
} catch (e) {
return '';
}
}
};
registerBidder(spec);
93 changes: 93 additions & 0 deletions test/spec/modules/kargoBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,97 @@ describe('kargo adapter tests', function () {
expect(resp).to.deep.equal(expectation);
});
});

describe('user sync handler', function() {
const clientId = '74c81cbb-7d07-46d9-be9b-68ccb291c949';
var shouldSimulateOutdatedBrowser, uid, isActuallyOutdatedBrowser;

beforeEach(() => {
uid = {};
shouldSimulateOutdatedBrowser = false;
isActuallyOutdatedBrowser = false;

// IE11 fails these tests in the Prebid test suite. Since this
// browser won't support any of this stuff we expect all user
// syncing to fail gracefully. Kargo is mobile only, so this
// doesn't really matter.
if (!window.crypto) {
isActuallyOutdatedBrowser = true;
} else {
sandbox.stub(crypto, 'getRandomValues').callsFake(function(buf) {
if (shouldSimulateOutdatedBrowser) {
throw new Error('Could not generate random values');
}
var bytes = [50, 5, 232, 133, 141, 55, 49, 57, 244, 126, 248, 44, 255, 38, 128, 0];
for (var i = 0; i < bytes.length; i++) {
buf[i] = bytes[i];
}
return buf;
});
}

sandbox.stub(spec, '_getUid').callsFake(function() {
return uid;
});
});

function getUserSyncsWhenAllowed() {
return spec.getUserSyncs({iframeEnabled: true});
}

function getUserSyncsWhenForbidden() {
return spec.getUserSyncs({});
}

function turnOnClientId() {
uid.clientId = clientId;
}

function simulateOutdatedBrowser() {
shouldSimulateOutdatedBrowser = true;
}

function getSyncUrl(index) {
return {
type: 'iframe',
url: `https://crb.kargo.com/api/v1/initsyncrnd/${clientId}?seed=3205e885-8d37-4139-b47e-f82cff268000&idx=${index}`
};
}

function getSyncUrls() {
var syncs = [];
for (var i = 0; i < 5; i++) {
syncs[i] = getSyncUrl(i);
}
return syncs;
}

function safelyRun(runExpectation) {
if (isActuallyOutdatedBrowser) {
expect(getUserSyncsWhenAllowed()).to.be.an('array').that.is.empty;
} else {
runExpectation();
}
}

it('handles user syncs when there is a client id', function() {
turnOnClientId();
safelyRun(() => expect(getUserSyncsWhenAllowed()).to.deep.equal(getSyncUrls()));
});

it('no user syncs when there is no client id', function() {
safelyRun(() => expect(getUserSyncsWhenAllowed()).to.be.an('array').that.is.empty);
});

it('no user syncs when there is outdated browser', function() {
turnOnClientId();
simulateOutdatedBrowser();
safelyRun(() => expect(getUserSyncsWhenAllowed()).to.be.an('array').that.is.empty);
});

it('no user syncs when no iframe syncing allowed', function() {
turnOnClientId();
safelyRun(() => expect(getUserSyncsWhenForbidden()).to.be.an('array').that.is.empty);
});
});
});