Skip to content

Commit

Permalink
Allow Doubleclick publishers to force on A4A in beta-test mode (#5613)
Browse files Browse the repository at this point in the history
* Draft of beta-tester override tag parameter.

* Made manual mode take precedence over publisher-override mode.

* Updates in response to reviews.

* Updates in response to reviews.

* Minor fixes from review.
  • Loading branch information
Terran Lane authored and lannka committed Oct 19, 2016
1 parent cea1401 commit b7d5e2d
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@

import {
googleAdsIsA4AEnabled,
EXPERIMENT_ATTRIBUTE,
isInManualExperiment,
} from '../../../ads/google/a4a/traffic-experiments';
import {getMode} from '../../../src/mode';
import {isProxyOrigin} from '../../../src/url';

/** @const {string} */
const DOUBLECLICK_A4A_EXPERIMENT_NAME = 'expDoubleclickA4A';
Expand Down Expand Up @@ -60,16 +64,39 @@ export const DOUBLECLICK_A4A_INTERNAL_EXPERIMENT_BRANCHES = {
experiment: '117152681',
};

/** @const {!../../../ads/google/a4a/traffic-experiments.ExperimentInfo} */
export const DOUBLECLICK_A4A_BETA_BRANCHES = {
control: '2077830',
experiment: '2077831',
};

export const BETA_ATTRIBUTE = 'data-use-beta-a4a-implementation';

/**
* @param {!Window} win
* @param {!Element} element
* @returns {boolean}
*/
export function doubleclickIsA4AEnabled(win, element) {
// Ensure not within remote.html iframe.
return !win.document.querySelector('meta[name=amp-3p-iframe-src]') &&
googleAdsIsA4AEnabled(
win, element, DOUBLECLICK_A4A_EXPERIMENT_NAME,
DOUBLECLICK_A4A_EXTERNAL_EXPERIMENT_BRANCHES,
DOUBLECLICK_A4A_INTERNAL_EXPERIMENT_BRANCHES);
if (!!win.document.querySelector('meta[name=amp-3p-iframe-src]')) {
return false;
}
const a4aRequested = element.hasAttribute(BETA_ATTRIBUTE);
// Note: Under this logic, a4aRequested shortcuts googleAdsIsA4AEnabled and,
// therefore, carves out of the experiment branches. Any publisher using this
// attribute will be excluded from the experiment altogether.
// TODO(tdrl): The "is this site eligible" logic has gotten scattered around
// and is now duplicated. It should be cleaned up and factored into a single,
// shared location.
const enableA4A = googleAdsIsA4AEnabled(
win, element, DOUBLECLICK_A4A_EXPERIMENT_NAME,
DOUBLECLICK_A4A_EXTERNAL_EXPERIMENT_BRANCHES,
DOUBLECLICK_A4A_INTERNAL_EXPERIMENT_BRANCHES) ||
(a4aRequested && (isProxyOrigin(win.location) ||
getMode(win).localDev || getMode(win).test));
if (enableA4A && a4aRequested && !isInManualExperiment(element)) {
element.setAttribute(EXPERIMENT_ATTRIBUTE,
DOUBLECLICK_A4A_BETA_BRANCHES.experiment);
}
return enableA4A;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/**
* Copyright 2016 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
doubleclickIsA4AEnabled,
DOUBLECLICK_A4A_EXTERNAL_EXPERIMENT_BRANCHES,
DOUBLECLICK_A4A_BETA_BRANCHES,
BETA_ATTRIBUTE,
} from '../doubleclick-a4a-config';
import {
EXPERIMENT_ATTRIBUTE,
isInManualExperiment,
} from '../../../../ads/google/a4a/traffic-experiments';
import {resetExperimentToggles_} from '../../../../src/experiments';
import {parseUrl} from '../../../../src/url';
import {createIframePromise} from '../../../../testing/iframe';
import * as sinon from 'sinon';

describe('doubleclick-a4a-config', () => {
let sandbox;
let mockWin;
// Captures the fixture built by createIframePromise().
let testFixture;

beforeEach(() => {
sandbox = sinon.sandbox.create();
mockWin = {
location: parseUrl('https://nowhere.org/a/place/page.html?s=foo&q=bar'),
document: {
querySelector: unused => {return null;},
},
crypto: {
subtle: true,
webkitSubtle: true,
},
};
return createIframePromise().then(i => { testFixture = i; });
});
afterEach(() => {
sandbox.restore();
resetExperimentToggles_();
});

describe('#doubleclickIsA4AEnabled', () => {
it('should enable a4a when requested and on CDN', () => {
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html');
const elem = testFixture.doc.createElement('div');
elem.setAttribute(BETA_ATTRIBUTE, 'true');
testFixture.doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.true;
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.equal(
DOUBLECLICK_A4A_BETA_BRANCHES.experiment);
});

it('should enable a4a when requested and in local dev', () => {
const elem = testFixture.doc.createElement('div');
elem.setAttribute(BETA_ATTRIBUTE, 'true');
mockWin.AMP_MODE = {localDev: true};
testFixture.doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.true;
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.equal(
DOUBLECLICK_A4A_BETA_BRANCHES.experiment);
});

it('should not enable a4a, even if requested, when on bad origin', () => {
const elem = testFixture.doc.createElement('div');
elem.setAttribute(BETA_ATTRIBUTE, 'true');
testFixture.doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.false;
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.not.be.ok;
});

it('should carve out remote.html, in spite of experiment override', () => {
const doc = testFixture.doc;
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html');
mockWin.document.querySelector = doc.querySelector.bind(doc);
const remoteTag = doc.createElement('meta');
remoteTag.setAttribute('name', 'amp-3p-iframe-src');
doc.head.appendChild(remoteTag);
const elem = doc.createElement('div');
elem.setAttribute(BETA_ATTRIBUTE, 'true');
doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.false;
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.not.be.ok;
});

[-1, 0, 1, 2].forEach(expFlagValue => {
it(`exp flag=${expFlagValue} should set eid attribute`, () => {
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html?exp=a4a:' +
String(expFlagValue));
const expectedEnabledState =
(expFlagValue == -1 || expFlagValue == 2);
const elem = testFixture.doc.createElement('div');
testFixture.doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.equal(
expectedEnabledState);
if (expFlagValue == 0) {
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.not.be.ok;
} else {
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.be.ok;
}
});

it(`should carve out remote.html, in spite of exp flag=${expFlagValue}`,
() => {
const doc = testFixture.doc;
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html?exp=a4a:' +
String(expFlagValue));
mockWin.document.querySelector = doc.querySelector.bind(doc);
const remoteTag = doc.createElement('meta');
remoteTag.setAttribute('name', 'amp-3p-iframe-src');
doc.head.appendChild(remoteTag);
const elem = doc.createElement('div');
doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.false;
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.not.be.ok;
});
});

[0, 1, 2].forEach(expFlagValue => {
it(`force a4a attribute should preempt exp flag=${expFlagValue}`, () => {
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html?exp=a4a:' +
String(expFlagValue));
const elem = testFixture.doc.createElement('div');
elem.setAttribute(BETA_ATTRIBUTE, 'true');
testFixture.doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.true;
expect(elem.getAttribute(EXPERIMENT_ATTRIBUTE)).to.equal(
DOUBLECLICK_A4A_BETA_BRANCHES.experiment);
});
});

it('manual experiment should win over force a4a attribute', () => {
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html?exp=a4a:-1');
const elem = testFixture.doc.createElement('div');
elem.setAttribute(BETA_ATTRIBUTE, 'true');
testFixture.doc.body.appendChild(elem);
expect(doubleclickIsA4AEnabled(mockWin, elem)).to.be.true;
expect(isInManualExperiment(elem)).to.be.true;
});

it('should not switch on other slot on page', () => {
const doc = testFixture.doc;
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html?exp=a4a:0');
const elem0 = doc.createElement('div');
elem0.setAttribute(BETA_ATTRIBUTE, 'true');
doc.body.appendChild(elem0);
const elem1 = doc.createElement('div');
doc.body.appendChild(elem1);
expect(doubleclickIsA4AEnabled(mockWin, elem0)).to.be.true;
expect(elem0.getAttribute(EXPERIMENT_ATTRIBUTE)).to.equal(
DOUBLECLICK_A4A_BETA_BRANCHES.experiment);
expect(doubleclickIsA4AEnabled(mockWin, elem1)).to.be.false;
expect(elem1.getAttribute(EXPERIMENT_ATTRIBUTE)).to.not.be.ok;
});

it('should not interfere with other slot on page', () => {
const doc = testFixture.doc;
mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html?exp=a4a:2');
const elem0 = doc.createElement('div');
elem0.setAttribute(BETA_ATTRIBUTE, 'true');
doc.body.appendChild(elem0);
const elem1 = doc.createElement('div');
doc.body.appendChild(elem1);
expect(doubleclickIsA4AEnabled(mockWin, elem0)).to.be.true;
expect(elem0.getAttribute(EXPERIMENT_ATTRIBUTE)).to.equal(
DOUBLECLICK_A4A_BETA_BRANCHES.experiment);
expect(doubleclickIsA4AEnabled(mockWin, elem1)).to.be.true;
expect(elem1.getAttribute(EXPERIMENT_ATTRIBUTE)).to.equal(
DOUBLECLICK_A4A_EXTERNAL_EXPERIMENT_BRANCHES.experiment);
});
});
});

0 comments on commit b7d5e2d

Please sign in to comment.