Skip to content

Commit

Permalink
Core: fill in video.plcmt when possible (#10438)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgirardi authored Sep 6, 2023
1 parent 9961f1c commit 3fa0dd6
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 103 deletions.
8 changes: 8 additions & 0 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {newMetrics, useMetrics} from './utils/perfMetrics.js';
import {defer, GreedyPromise} from './utils/promise.js';
import {enrichFPD} from './fpd/enrichment.js';
import {allConsent} from './consentHandler.js';
import {fillVideoDefaults} from './video.js';

const pbjsInstance = getGlobal();
const { triggerUserSyncs } = userSync;
Expand Down Expand Up @@ -269,6 +270,12 @@ export const checkAdUnitSetup = hook('sync', function (adUnits) {
return validatedAdUnits;
}, 'checkAdUnitSetup');

function fillAdUnitDefaults(adUnits) {
if (FEATURES.VIDEO) {
adUnits.forEach(au => fillVideoDefaults(au))
}
}

/// ///////////////////////////////
// //
// Start Public APIs //
Expand Down Expand Up @@ -658,6 +665,7 @@ pbjsInstance.requestBids = (function() {

export const startAuction = hook('async', function ({ bidsBackHandler, timeout: cbTimeout, adUnits, ttlBuffer, adUnitCodes, labels, auctionId, ortb2Fragments, metrics, defer } = {}) {
const s2sBidders = getS2SBidderSet(config.getConfig('s2sConfig') || []);
fillAdUnitDefaults(adUnits);
adUnits = useMetrics(metrics).measureTime('requestBids.validate', () => checkAdUnitSetup(adUnits));

function auctionDone(bids, timedOut, auctionId) {
Expand Down
30 changes: 13 additions & 17 deletions src/video.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import adapterManager from './adapterManager.js';
import { deepAccess, logError } from './utils.js';
import { config } from '../src/config.js';
import {includes} from './polyfill.js';
import { hook } from './hook.js';
import {deepAccess, logError} from './utils.js';
import {config} from '../src/config.js';
import {hook} from './hook.js';
import {auctionManager} from './auctionManager.js';

const VIDEO_MEDIA_TYPE = 'video';
export const OUTSTREAM = 'outstream';
export const INSTREAM = 'instream';

/**
* Helper functions for working with video-enabled adUnits
*/
export const videoAdUnit = adUnit => {
const mediaType = adUnit.mediaType === VIDEO_MEDIA_TYPE;
const mediaTypes = deepAccess(adUnit, 'mediaTypes.video');
return mediaType || mediaTypes;
};
export const videoBidder = bid => includes(adapterManager.videoAdapters, bid.bidder);
export const hasNonVideoBidder = adUnit =>
adUnit.bids.filter(bid => !videoBidder(bid)).length;
export function fillVideoDefaults(adUnit) {
const video = adUnit?.mediaTypes?.video;
if (video != null && video.plcmt == null) {
if (video.context === OUTSTREAM || [2, 3, 4].includes(video.placement)) {
video.plcmt = 4;
} else if (video.context !== OUTSTREAM && [2, 6].includes(video.playmethod)) {
video.plcmt = 2;
}
}
}

/**
* @typedef {object} VideoBid
Expand Down
244 changes: 158 additions & 86 deletions test/spec/video_spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isValidVideoBid } from 'src/video.js';
import {fillVideoDefaults, isValidVideoBid} from 'src/video.js';
import {hook} from '../../src/hook.js';
import {stubAuctionIndex} from '../helpers/indexStub.js';

Expand All @@ -7,97 +7,169 @@ describe('video.js', function () {
hook.ready();
});

it('validates valid instream bids', function () {
const bid = {
adId: '456xyz',
vastUrl: 'http://www.example.com/vastUrl',
transactionId: 'au'
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'instream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(true);
});
describe('fillVideoDefaults', () => {
function fillDefaults(videoMediaType = {}) {
const adUnit = {mediaTypes: {video: videoMediaType}};
fillVideoDefaults(adUnit);
return adUnit.mediaTypes.video;
}

it('catches invalid instream bids', function () {
const bid = {
transactionId: 'au'
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'instream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(false);
});
describe('should set plcmt = 4 when', () => {
it('context is "outstream"', () => {
expect(fillDefaults({context: 'outstream'})).to.eql({
context: 'outstream',
plcmt: 4
})
});
[2, 3, 4].forEach(placement => {
it(`placemement is "${placement}"`, () => {
expect(fillDefaults({placement})).to.eql({
placement,
plcmt: 4
});
})
});
});
describe('should set plcmt = 2 when', () => {
[2, 6].forEach(playmethod => {
it(`playmethod is "${playmethod}"`, () => {
expect(fillDefaults({playmethod})).to.eql({
playmethod,
plcmt: 2,
});
});
});
});
describe('should not set plcmt when', () => {
Object.entries({
'it was set by pub (context=outstream)': {
expected: 1,
video: {
context: 'outstream',
plcmt: 1
}
},
'it was set by pub (placement=2)': {
expected: 1,
video: {
placement: 2,
plcmt: 1
}
},
'placement not in 2, 3, 4': {
expected: undefined,
video: {
placement: 1
}
},
'it was set by pub (playmethod=2)': {
expected: 1,
video: {
plcmt: 1,
playmethod: 2
}
}
}).forEach(([t, {expected, video}]) => {
it(t, () => {
expect(fillDefaults(video).plcmt).to.eql(expected);
})
})
})
})

it('catches invalid bids when prebid-cache is disabled', function () {
const adUnits = [{
transactionId: 'au',
bidder: 'vastOnlyVideoBidder',
mediaTypes: {video: {}},
}];
describe('isValidVideoBid', () => {
it('validates valid instream bids', function () {
const bid = {
adId: '456xyz',
vastUrl: 'http://www.example.com/vastUrl',
transactionId: 'au'
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'instream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(true);
});

const valid = isValidVideoBid({ transactionId: 'au', vastXml: '<xml>vast</xml>' }, {index: stubAuctionIndex({adUnits})});
it('catches invalid instream bids', function () {
const bid = {
transactionId: 'au'
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'instream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(false);
});

expect(valid).to.equal(false);
});
it('catches invalid bids when prebid-cache is disabled', function () {
const adUnits = [{
transactionId: 'au',
bidder: 'vastOnlyVideoBidder',
mediaTypes: {video: {}},
}];

it('validates valid outstream bids', function () {
const bid = {
transactionId: 'au',
renderer: {
url: 'render.url',
render: () => true,
}
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'outstream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(true);
});
const valid = isValidVideoBid({ transactionId: 'au', vastXml: '<xml>vast</xml>' }, {index: stubAuctionIndex({adUnits})});

it('validates valid outstream bids with a publisher defined renderer', function () {
const bid = {
transactionId: 'au',
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {
context: 'outstream',
expect(valid).to.equal(false);
});

it('validates valid outstream bids', function () {
const bid = {
transactionId: 'au',
renderer: {
url: 'render.url',
render: () => true,
}
},
renderer: {
url: 'render.url',
render: () => true,
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(true);
});
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'outstream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(true);
});

it('catches invalid outstream bids', function () {
const bid = {
transactionId: 'au',
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'outstream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(false);
});
it('validates valid outstream bids with a publisher defined renderer', function () {
const bid = {
transactionId: 'au',
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {
context: 'outstream',
}
},
renderer: {
url: 'render.url',
render: () => true,
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(true);
});

it('catches invalid outstream bids', function () {
const bid = {
transactionId: 'au',
};
const adUnits = [{
transactionId: 'au',
mediaTypes: {
video: {context: 'outstream'}
}
}];
const valid = isValidVideoBid(bid, {index: stubAuctionIndex({adUnits})});
expect(valid).to.equal(false);
});
})
});

0 comments on commit 3fa0dd6

Please sign in to comment.