Skip to content

Commit

Permalink
Kimberlite Bidder Adapter: initial commit (prebid#11032)
Browse files Browse the repository at this point in the history
* Kimberlite bid adapter (#1)

* initial: bid adapter

* styling

* Fix: lint (#2)

* Fix: lint (prebid#4)

* review fixes (prebid#6)

* Change: filling request.ext.prebid section (prebid#7)

---------

Co-authored-by: Oleg <oleg.s@solta.io>
  • Loading branch information
solta-dev and os-solta authored Feb 20, 2024
1 parent be08dc8 commit 0606e77
Show file tree
Hide file tree
Showing 3 changed files with 278 additions and 0 deletions.
71 changes: 71 additions & 0 deletions modules/kimberliteBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js'
import { deepSetValue } from '../src/utils.js';

const VERSION = '1.0.0';

const BIDDER_CODE = 'kimberlite';
const METHOD = 'POST';
const ENDPOINT_URL = 'https://kimberlite.io/rtb/bid/pbjs';

const VERSION_INFO = {
ver: '$prebid.version$',
adapterVer: `${VERSION}`
};

const converter = ortbConverter({
context: {
mediaType: BANNER,
netRevenue: true,
ttl: 300
},

request(buildRequest, imps, bidderRequest, context) {
const bidRequest = buildRequest(imps, bidderRequest, context);
deepSetValue(bidRequest, 'site.publisher.domain', bidderRequest.refererInfo.domain);
deepSetValue(bidRequest, 'site.page', bidderRequest.refererInfo.page);
deepSetValue(bidRequest, 'ext.prebid.ver', VERSION_INFO.ver);
deepSetValue(bidRequest, 'ext.prebid.adapterVer', VERSION_INFO.adapterVer);
bidRequest.at = 1;
return bidRequest;
},

imp (buildImp, bidRequest, context) {
const imp = buildImp(bidRequest, context);
imp.tagid = bidRequest.params.placementId;
return imp;
}
});

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER],

isBidRequestValid: (bidRequest = {}) => {
const { params, mediaTypes } = bidRequest;
let isValid = Boolean(params && params.placementId);
if (mediaTypes && mediaTypes[BANNER]) {
isValid = isValid && Boolean(mediaTypes[BANNER].sizes);
} else {
isValid = false;
}

return isValid;
},

buildRequests: function (bidRequests, bidderRequest) {
return {
method: METHOD,
url: ENDPOINT_URL,
data: converter.toORTB({ bidderRequest, bidRequests })
}
},

interpretResponse(serverResponse, bidRequest) {
const bids = converter.fromORTB({response: serverResponse.body, request: bidRequest.data}).bids;
return bids;
}
};

registerBidder(spec);
36 changes: 36 additions & 0 deletions modules/kimberliteBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Overview

```markdown
Module Name: Kimberlite Bid Adapter
Module Type: Bidder Adapter
Maintainer: dev@solta.io
```

# Description

Kimberlite exchange adapter.

# Test Parameters

## Banner AdUnit

```javascript
var adUnits = [
{
code: 'test-div',
mediaTypes: {
banner: {
sizes: [[320, 250], [640, 480]],
}
},
bids: [
{
bidder: "kimberlite",
params: {
placementId: 'testBanner'
}
}
]
}
]
```
171 changes: 171 additions & 0 deletions test/spec/modules/kimberliteBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { spec } from 'modules/kimberliteBidAdapter.js';
import { assert } from 'chai';
import { BANNER } from '../../../src/mediaTypes.js';

const BIDDER_CODE = 'kimberlite';

describe('kimberliteBidAdapter', function () {
const sizes = [[640, 480]];

describe('isBidRequestValid', function () {
let bidRequest;

beforeEach(function () {
bidRequest = {
mediaTypes: {
[BANNER]: {
sizes: [[320, 240]]
}
},
params: {
placementId: 'test-placement'
}
};
});

it('pass on valid bidRequest', function () {
assert.isTrue(spec.isBidRequestValid(bidRequest));
});

it('fails on missed placementId', function () {
delete bidRequest.params.placementId;
assert.isFalse(spec.isBidRequestValid(bidRequest));
});

it('fails on empty banner', function () {
delete bidRequest.mediaTypes.banner;
assert.isFalse(spec.isBidRequestValid(bidRequest));
});

it('fails on empty banner.sizes', function () {
delete bidRequest.mediaTypes.banner.sizes;
assert.isFalse(spec.isBidRequestValid(bidRequest));
});

it('fails on empty request', function () {
assert.isFalse(spec.isBidRequestValid());
});
});

describe('buildRequests', function () {
let bidRequests, bidderRequest;

beforeEach(function () {
bidRequests = [{
mediaTypes: {
[BANNER]: {sizes: sizes}
},
params: {
placementId: 'test-placement'
}
}];

bidderRequest = {
refererInfo: {
domain: 'example.com',
page: 'https://www.example.com/test.html',
},
bids: [{
mediaTypes: {
[BANNER]: {sizes: sizes}
}
}]
};
});

it('valid bid request', function () {
const bidRequest = spec.buildRequests(bidRequests, bidderRequest);
assert.equal(bidRequest.method, 'POST');
assert.ok(bidRequest.data);

const requestData = bidRequest.data;
expect(requestData.site.page).to.equal(bidderRequest.refererInfo.page);
expect(requestData.site.publisher.domain).to.equal(bidderRequest.refererInfo.domain);

expect(requestData.imp).to.be.an('array').and.is.not.empty;

expect(requestData.ext).to.be.an('Object').and.have.all.keys('prebid');
expect(requestData.ext.prebid).to.be.an('Object').and.have.all.keys('ver', 'adapterVer');

const impData = requestData.imp[0];
expect(impData.banner).is.to.be.an('Object').and.have.all.keys(['format', 'topframe']);

const bannerData = impData.banner;
expect(bannerData.format).to.be.an('array').and.is.not.empty;

const formatData = bannerData.format[0];
expect(formatData).to.be.an('Object').and.have.all.keys('w', 'h');

assert.equal(formatData.w, sizes[0][0]);
assert.equal(formatData.h, sizes[0][1]);
});
});

describe('interpretResponse', function () {
let bidderResponse, bidderRequest, bidRequest, expectedBid;

const requestId = '07fba8b0-8812-4dc6-b91e-4a525d81729c';
const bidId = '222209853178';
const impId = 'imp-id';
const crId = 'creative-id';
const adm = '<a href="http://test.landing.com">landing</a>';

beforeEach(function () {
bidderResponse = {
body: {
id: requestId,
seatbid: [{
bid: [{
crid: crId,
id: bidId,
impid: impId,
price: 1,
adm: adm
}]
}]
}
};

bidderRequest = {
refererInfo: {
domain: 'example.com',
page: 'https://www.example.com/test.html',
},
bids: [{
bidId: impId,
mediaTypes: {
[BANNER]: {sizes: sizes}
},
params: {
placementId: 'test-placement'
}
}]
};

expectedBid = {
mediaType: 'banner',
requestId: 'imp-id',
seatBidId: '222209853178',
cpm: 1,
creative_id: 'creative-id',
creativeId: 'creative-id',
ttl: 300,
netRevenue: true,
ad: adm,
meta: {}
};

bidRequest = spec.buildRequests(bidderRequest.bids, bidderRequest);
});

it('pass on valid request', function () {
const bids = spec.interpretResponse(bidderResponse, bidRequest);
assert.deepEqual(bids[0], expectedBid);
});

it('fails on empty response', function () {
const bids = spec.interpretResponse({body: ''}, bidRequest);
assert.empty(bids);
});
});
});

0 comments on commit 0606e77

Please sign in to comment.