Skip to content

Commit 7f43556

Browse files
Magnite Analytics Adapter : add seat non bid handling (#9696)
* Return all bids * Adjust findMatch function * Return all buds unit testing * Responds to review comments * Unit test adjustments * Remove extra line for lint * minor changes * doh --------- Co-authored-by: Robert Ray Martinez III <[email protected]>
1 parent 584af55 commit 7f43556

File tree

2 files changed

+205
-4
lines changed

2 files changed

+205
-4
lines changed

modules/magniteAnalyticsAdapter.js

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ const {
5656
BIDDER_DONE,
5757
BID_TIMEOUT,
5858
BID_WON,
59-
BILLABLE_EVENT
59+
BILLABLE_EVENT,
60+
SEAT_NON_BID
6061
},
6162
STATUS: {
6263
GOOD,
@@ -483,7 +484,7 @@ const findMatchingAdUnitFromAuctions = (matchesFunction, returnFirstMatch) => {
483484
}
484485
}
485486
return matches;
486-
}
487+
};
487488

488489
const getRenderingIds = bidWonData => {
489490
// if bid caching off -> return the bidWon auction id
@@ -840,7 +841,16 @@ magniteAdapter.track = ({ eventType, args }) => {
840841
auctionEntry.floors.dealsEnforced = args.floorData.enforcements.floorDeals;
841842
}
842843

843-
// Log error if no matching bid!
844+
// no-bid from server. report it!
845+
if (!bid && args.seatBidId) {
846+
bid = adUnit.bids[args.seatBidId] = {
847+
bidder: args.bidderCode,
848+
source: 'server',
849+
bidId: args.seatBidId,
850+
unknownBid: true
851+
};
852+
}
853+
844854
if (!bid) {
845855
logError(`${MODULE_NAME}: Could not find associated bid request for bid response with requestId: `, args.requestId);
846856
break;
@@ -871,6 +881,9 @@ magniteAdapter.track = ({ eventType, args }) => {
871881
bid.pbsBidId = pbsBidId;
872882
}
873883
break;
884+
case SEAT_NON_BID:
885+
handleNonBidEvent(args);
886+
break;
874887
case BIDDER_DONE:
875888
const serverError = deepAccess(args, 'serverErrors.0');
876889
const serverResponseTimeMs = args.serverResponseTimeMs;
@@ -958,6 +971,66 @@ magniteAdapter.track = ({ eventType, args }) => {
958971
}
959972
};
960973

974+
const handleNonBidEvent = function(args) {
975+
const {seatnonbid, auctionId} = args;
976+
const auction = deepAccess(cache, `auctions.${auctionId}.auction`);
977+
// if no auction just bail
978+
if (!auction) {
979+
logWarn(`Unable to match nonbid to auction`);
980+
return;
981+
}
982+
const adUnits = auction.adUnits;
983+
seatnonbid.forEach(seatnonbid => {
984+
let {seat} = seatnonbid;
985+
seatnonbid.nonbid.forEach(nonbid => {
986+
try {
987+
const {status, impid} = nonbid;
988+
const matchingTid = Object.keys(adUnits).find(tid => adUnits[tid].adUnitCode === impid);
989+
const adUnit = adUnits[matchingTid];
990+
const statusInfo = statusMap[status] || { status: 'no-bid' };
991+
adUnit.bids[generateUUID()] = {
992+
bidder: seat,
993+
source: 'server',
994+
isSeatNonBid: true,
995+
clientLatencyMillis: Date.now() - auction.auctionStart,
996+
...statusInfo
997+
};
998+
} catch (error) {
999+
logWarn(`Unable to match nonbid to adUnit`);
1000+
}
1001+
});
1002+
});
1003+
};
1004+
1005+
const statusMap = {
1006+
0: {
1007+
status: 'no-bid'
1008+
},
1009+
100: {
1010+
status: 'error',
1011+
error: {
1012+
code: 'request-error',
1013+
description: 'general error'
1014+
}
1015+
},
1016+
101: {
1017+
status: 'error',
1018+
error: {
1019+
code: 'timeout-error',
1020+
description: 'prebid server timeout'
1021+
}
1022+
},
1023+
200: {
1024+
status: 'rejected'
1025+
},
1026+
202: {
1027+
status: 'rejected'
1028+
},
1029+
301: {
1030+
status: 'rejected-ipf'
1031+
}
1032+
};
1033+
9611034
adapterManager.registerAnalyticsAdapter({
9621035
adapter: magniteAdapter,
9631036
code: 'magnite',

test/spec/modules/magniteAnalyticsAdapter_spec.js

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ const {
2828
BIDDER_DONE,
2929
BID_WON,
3030
BID_TIMEOUT,
31-
BILLABLE_EVENT
31+
BILLABLE_EVENT,
32+
SEAT_NON_BID
3233
}
3334
} = CONSTANTS;
3435

@@ -160,6 +161,16 @@ const MOCK = {
160161
'status': 'rendered',
161162
getStatusCode: () => 1,
162163
},
164+
SEAT_NON_BID: {
165+
auctionId: '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d',
166+
seatnonbid: [{
167+
seat: 'rubicon',
168+
nonbid: [{
169+
status: 1,
170+
impid: 'box'
171+
}]
172+
}]
173+
},
163174
AUCTION_END: {
164175
'auctionId': '99785e47-a7c8-4c8a-ae05-ef1c717a4b4d',
165176
'auctionEnd': 1658868384019,
@@ -2039,4 +2050,121 @@ describe('magnite analytics adapter', function () {
20392050
}
20402051
})
20412052
});
2053+
2054+
describe('BID_RESPONSE events', () => {
2055+
beforeEach(() => {
2056+
magniteAdapter.enableAnalytics({
2057+
options: {
2058+
endpoint: '//localhost:9999/event',
2059+
accountId: 1001
2060+
}
2061+
});
2062+
config.setConfig({ rubicon: { updatePageView: true } });
2063+
});
2064+
2065+
it('should add a no-bid bid to the add unit if it recieves one from the server', () => {
2066+
const bidResponse = utils.deepClone(MOCK.BID_RESPONSE);
2067+
const auctionInit = utils.deepClone(MOCK.AUCTION_INIT);
2068+
2069+
bidResponse.requestId = 'fakeId';
2070+
bidResponse.seatBidId = 'fakeId';
2071+
2072+
bidResponse.requestId = 'fakeId';
2073+
events.emit(AUCTION_INIT, auctionInit);
2074+
events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
2075+
events.emit(BID_RESPONSE, bidResponse)
2076+
events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
2077+
events.emit(AUCTION_END, MOCK.AUCTION_END);
2078+
clock.tick(rubiConf.analyticsBatchTimeout + 1000);
2079+
2080+
let message = JSON.parse(server.requests[0].requestBody);
2081+
expect(utils.generateUUID.called).to.equal(true);
2082+
2083+
expect(message.auctions[0].adUnits[0].bids[1]).to.deep.equal(
2084+
{
2085+
bidder: 'rubicon',
2086+
source: 'server',
2087+
status: 'success',
2088+
bidResponse: {
2089+
'bidPriceUSD': 3.4,
2090+
'dimensions': {
2091+
'height': 250,
2092+
'width': 300
2093+
},
2094+
'mediaType': 'banner'
2095+
},
2096+
oldBidId: 'fakeId',
2097+
unknownBid: true,
2098+
bidId: 'fakeId',
2099+
clientLatencyMillis: 271
2100+
}
2101+
);
2102+
});
2103+
});
2104+
2105+
describe('SEAT_NON_BID events', () => {
2106+
let seatnonbid;
2107+
2108+
const runNonBidAuction = () => {
2109+
events.emit(AUCTION_INIT, MOCK.AUCTION_INIT);
2110+
events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
2111+
events.emit(SEAT_NON_BID, seatnonbid)
2112+
events.emit(BIDDER_DONE, MOCK.BIDDER_DONE);
2113+
events.emit(AUCTION_END, MOCK.AUCTION_END);
2114+
clock.tick(rubiConf.analyticsBatchTimeout + 1000);
2115+
};
2116+
const checkStatusAgainstCode = (status, code, error, index) => {
2117+
seatnonbid.seatnonbid[0].nonbid[0].status = code;
2118+
runNonBidAuction();
2119+
let message = JSON.parse(server.requests[index].requestBody);
2120+
let bid = message.auctions[0].adUnits[0].bids[1];
2121+
2122+
if (error) {
2123+
expect(bid.error).to.deep.equal(error);
2124+
} else {
2125+
expect(bid.error).to.equal(undefined);
2126+
}
2127+
expect(bid.source).to.equal('server');
2128+
expect(bid.status).to.equal(status);
2129+
expect(bid.isSeatNonBid).to.equal(true);
2130+
};
2131+
beforeEach(() => {
2132+
magniteAdapter.enableAnalytics({
2133+
options: {
2134+
endpoint: '//localhost:9999/event',
2135+
accountId: 1001
2136+
}
2137+
});
2138+
seatnonbid = utils.deepClone(MOCK.SEAT_NON_BID);
2139+
});
2140+
2141+
it('adds seatnonbid info to bids array', () => {
2142+
runNonBidAuction();
2143+
let message = JSON.parse(server.requests[0].requestBody);
2144+
2145+
expect(message.auctions[0].adUnits[0].bids[1]).to.deep.equal(
2146+
{
2147+
bidder: 'rubicon',
2148+
source: 'server',
2149+
status: 'no-bid',
2150+
isSeatNonBid: true,
2151+
clientLatencyMillis: -139101369960
2152+
}
2153+
);
2154+
});
2155+
2156+
it('adjusts the status according to the status map', () => {
2157+
const statuses = [
2158+
{code: 0, status: 'no-bid'},
2159+
{code: 100, status: 'error', error: {code: 'request-error', description: 'general error'}},
2160+
{code: 101, status: 'error', error: {code: 'timeout-error', description: 'prebid server timeout'}},
2161+
{code: 200, status: 'rejected'},
2162+
{code: 202, status: 'rejected'},
2163+
{code: 301, status: 'rejected-ipf'}
2164+
];
2165+
statuses.forEach((info, index) => {
2166+
checkStatusAgainstCode(info.status, info.code, info.error, index);
2167+
});
2168+
});
2169+
});
20422170
});

0 commit comments

Comments
 (0)