-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Price floors new schema support AB Test #5390
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -341,12 +341,12 @@ function injectFakeServerEndpointDev() { | |
|
||
function startFakeServer() { | ||
const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]); | ||
fakeServer.stdout.on('data', (data) => { | ||
console.log(`stdout: ${data}`); | ||
}); | ||
fakeServer.stderr.on('data', (data) => { | ||
console.log(`stderr: ${data}`); | ||
}); | ||
fakeServer.stdout.on('data', (data) => { | ||
console.log(`stdout: ${data}`); | ||
}); | ||
fakeServer.stderr.on('data', (data) => { | ||
console.log(`stderr: ${data}`); | ||
}); | ||
} | ||
|
||
// support tasks | ||
|
@@ -372,6 +372,7 @@ gulp.task('build', gulp.series(clean, 'build-bundle-prod')); | |
gulp.task('build-postbid', gulp.series(escapePostbidConfig, buildPostbid)); | ||
|
||
gulp.task('serve', gulp.series(clean, lint, gulp.parallel('build-bundle-dev', watch, test))); | ||
gulp.task('serve-fast', gulp.series(clean, gulp.parallel('build-bundle-dev', watch))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I am just trying to test via my E2E test pages having to wait several minutes for lint + test is a little much. Thought others might use a similar local edit, so why not merge it in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will come in handy! |
||
gulp.task('serve-fake', gulp.series(clean, gulp.parallel('build-bundle-dev', watch), injectFakeServerEndpointDev, test, startFakeServer)); | ||
|
||
gulp.task('default', gulp.series(clean, makeWebpackPkg)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -295,11 +295,29 @@ export function updateAdUnitsForAuction(adUnits, floorData, auctionId) { | |
}); | ||
} | ||
|
||
export function pickRandomModel(modelGroups, weightSum) { | ||
// we loop through the models subtracting the current model weight from our random number | ||
// once we are at or below zero, we return the associated model | ||
let random = Math.floor(Math.random() * weightSum + 1) | ||
for (let i = 0; i < modelGroups.length; i++) { | ||
random -= modelGroups[i].modelWeight; | ||
if (random <= 0) { | ||
return modelGroups[i]; | ||
} | ||
} | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is a jsbin to test this function. Weights do not need to add up to 100. Only shown in jsbin for clarity. |
||
|
||
/** | ||
* @summary Updates the adUnits accordingly and returns the necessary floorsData for the current auction | ||
*/ | ||
export function createFloorsDataForAuction(adUnits, auctionId) { | ||
let resolvedFloorsData = utils.deepClone(_floorsConfig); | ||
// if using schema 2 pick a model here: | ||
if (utils.deepAccess(resolvedFloorsData, 'data.floorsSchemaVersion') === 2) { | ||
// merge the models specific stuff into the top level data settings (now it looks like floorsSchemaVersion 1!) | ||
let { modelGroups, ...rest } = resolvedFloorsData.data; | ||
resolvedFloorsData.data = Object.assign(rest, pickRandomModel(modelGroups, rest.modelWeightSum)); | ||
} | ||
|
||
// if we do not have a floors data set, we will try to use data set on adUnits | ||
let useAdUnitData = Object.keys(utils.deepAccess(resolvedFloorsData, 'data.values') || {}).length === 0; | ||
|
@@ -372,6 +390,36 @@ function validateRules(floorsData, numFields, delimiter) { | |
return Object.keys(floorsData.values).length > 0; | ||
} | ||
|
||
function modelIsValid(model) { | ||
// schema.fields has only allowed attributes | ||
if (!validateSchemaFields(utils.deepAccess(model, 'schema.fields'))) { | ||
return false; | ||
} | ||
return validateRules(model, model.schema.fields.length, model.schema.delimiter || '|') | ||
} | ||
|
||
/** | ||
* @summary Mapping of floor schema version to it's corresponding validation | ||
*/ | ||
const floorsSchemaValidation = { | ||
1: data => modelIsValid(data), | ||
2: data => { | ||
// model groups should be an array with at least one element | ||
if (!Array.isArray(data.modelGroups) || data.modelGroups.length === 0) { | ||
return false; | ||
} | ||
// every model should have valid schema, as well as an accompanying modelWeight | ||
data.modelWeightSum = 0; | ||
return data.modelGroups.every(model => { | ||
if (typeof model.modelWeight === 'number' && modelIsValid(model)) { | ||
data.modelWeightSum += model.modelWeight; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* @summary Fields array should have at least one entry and all should match allowed fields | ||
* Each rule in the values array should have a 'key' and 'floor' param | ||
|
@@ -382,11 +430,12 @@ export function isFloorsDataValid(floorsData) { | |
if (typeof floorsData !== 'object') { | ||
return false; | ||
} | ||
// schema.fields has only allowed attributes | ||
if (!validateSchemaFields(utils.deepAccess(floorsData, 'schema.fields'))) { | ||
floorsData.floorsSchemaVersion = floorsData.floorsSchemaVersion || 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. default to version 1 for backwards compat |
||
if (typeof floorsSchemaValidation[floorsData.floorsSchemaVersion] !== 'function') { | ||
utils.logError(`${MODULE_NAME}: Unknown floorsSchemaVersion: `, floorsData.floorsSchemaVersion); | ||
return false; | ||
} | ||
return validateRules(floorsData, floorsData.schema.fields.length, floorsData.schema.delimiter || '|') | ||
return floorsSchemaValidation[floorsData.floorsSchemaVersion](floorsData); | ||
} | ||
|
||
/** | ||
|
@@ -458,7 +507,13 @@ export function handleFetchResponse(fetchResponse) { | |
floorResponse = fetchResponse; | ||
} | ||
// Update the global floors object according to the fetched data | ||
_floorsConfig.data = parseFloorData(floorResponse, 'fetch') || _floorsConfig.data; | ||
const fetchData = parseFloorData(floorResponse, 'fetch'); | ||
if (fetchData) { | ||
// set .data to it | ||
_floorsConfig.data = fetchData; | ||
// set skipRate override if necessary | ||
_floorsConfig.skipRate = utils.isNumber(fetchData.skipRate) ? fetchData.skipRate : _floorsConfig.skipRate; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We were not honoring fetch level skip rates, which is a bug. Need to get this out asap. Added a test to confirm. |
||
} | ||
|
||
// if any auctions are waiting for fetch to finish, we need to continue them! | ||
resumeDelayedAuctions(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my editor keeps yelling at me about this so I just fixed it.