Skip to content

Start experiment to Add Fast Fetch support to canonical AMP pages for DoubleClick#11063

Merged
keithwrightbos merged 7 commits intoampproject:masterfrom
google:frizz-canonical-ff-support
Aug 30, 2017
Merged

Start experiment to Add Fast Fetch support to canonical AMP pages for DoubleClick#11063
keithwrightbos merged 7 commits intoampproject:masterfrom
google:frizz-canonical-ff-support

Conversation

@bradfrizzell
Copy link
Copy Markdown
Contributor

This change will start an experiment to add Fast Fetch support for Canonical AMP pages with DRX

return supportsNativeCrypto &&
(googleCdnProxyRegex.test(win.location.origin) || getMode(win).localDev ||
getMode(win).test);
return win.crypto && (win.crypto.subtle || win.crypto.webkitSubtle);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't change this otherwise AdSense would lose is AMP cache enforcement. You need to move the cdn check to a separate function so that you can check separately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

isTrafficEligible: () => true,
branches: [DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL_CONTROL,
DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL],
DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a separate experiment name with separate call to randomlySelectUnsetExperiments. You can use its results explicitly to determine FF eligibility (no need to include with other experiment selection) as those are isolated to AMP cache pages.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return false;
let singleton;

export class DoubleclickA4aEligibility {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this visibleForTesting

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

element.hasAttribute('useSameDomainRenderingUntilDeprecated') ||
!isGoogleAdsA4AValidEnvironment(win)) {
return false;
let singleton;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you can't assign the singleton immediately and make const?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

dev().info(TAG, `beta forced a4a selection ${element}`);
return true;

supportsCrypto(win) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc here and throughout

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

isA4aEnabled(win, element) {
element = element;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wha? you're assigning it to itself?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guaranteeing that it is who it says it is. Can't trust variables these days.

jk jk that was a messed up find/replace. Removed!

* @param {!Element} element
* @param {?string} experimentId
* @param {!Array} validBranches
* @param {!string} experimentName}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs return doc

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

experimentId = URL_EXPERIMENT_MAPPING[urlExperimentId];
dev().info(
TAG, `url experiment selection ${urlExperimentId}: ${experimentId}.`);
return this.addAndForceExperiment(win, element, experimentId, [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function forces the experimentId given (if present) and then returns if the experimentId is in the array? Wouldn't that cause holdback external control to use FF?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holdback external control should be using FF. That's the correct behavior.

*/
export function doubleclickIsA4AEnabled(win, element) {
const eligibilityChecker = new DoubleclickA4aEligibility();
return eligibilityChecker.isA4aEnabled(win, element);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return singleton.isA4AEnabled(win, element);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/** @visibleForTesting */
export class DoubleclickA4aEligibility {
constructor() {
return singleton;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_CONTROL,
DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_EXPERIMENT,
], DFP_CANONICAL_FF_EXPERIMENT_NAME);
if (experimentId) {
Copy link
Copy Markdown
Contributor

@keithwrightbos keithwrightbos Aug 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just have an else:

let experimentName = DFP_CANONICAL_FF_EXPERIMENT_NAME;
if (!this.isCdnProxy(win)) {
    experimentId = <select into canonical exp>
} else {
    experimentName = DOUBLECLICK_A4A_EXPERIMENT_NAME;
    if (element.hasAttribute...
}
if (experimentId) {
   addExperimentIdToElement(experimentId, element);
   forceExperimentBranch(win, experimentName, experimentId)
}
return ![DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_CONTROL,
      DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_EXTERNAL,
       DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL,
       DOUBLECLICK_EXPERIMENT_FEATURE.SFG_CONTROL_ID,
       DOUBLECLICK_EXPERIMENT_FEATURE.SFG_EXP_ID].includes(experimentId);


Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

DOUBLECLICK_EXPERIMENT_FEATURE.SFG_EXP_ID].includes(experimentId);
}

const singleton = new DoubleclickA4aEligibility();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html');
it('should enable a4a when native crypto is supported', () => {
forceExperimentBranch(mockWin, DFP_CANONICAL_FF_EXPERIMENT_NAME,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we wouldn't force anymore. Instead we would setup stub for experiment selection function and get experiment functions returning the values we want combined withArgs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it better to stub than to force the experiment branch? Seems like it would be a more useful test for catching changes if we call the actual experiment selection

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, see my previous comment that we do not currently test experiment selection at all.

it('should enable a4a when requested and in local dev', () => {
it('should not enable a4a when native crypto is not supported', () => {
const instance = new DoubleclickA4aEligibility();
sandbox.stub(instance, 'supportsCrypto', () => false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this works give you never pass instance to anything. I would have expected:

sandbox.stub(DoubleclickA4aEligibility.prototype, 'supportsCrypto').returns(false);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works because it's a singleton, but I can do it the other way if this way is unclear

const supportsNativeCrypto = win.crypto &&
(win.crypto.subtle || win.crypto.webkitSubtle);
const googleCdnProxyRegex =
/^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we consisted about the domain cdn.amproject.org.foo.com? Seems like we should guard against that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org((\/.*)|($))+ would work, please check it though

/** @const {string} */
export const BETA_EXPERIMENT_ID = '2077831';

/** @visibleForTesting */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine in the same comment as description

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

!isGoogleAdsA4AValidEnvironment(win)) {
return false;
export class DoubleclickA4aEligibility {
constructor() {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure you need an empty constructor?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

*/
isCdnProxy(win) {
const googleCdnProxyRegex =
/^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure if you tighten you do so here as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

isCdnProxy(win) {
const googleCdnProxyRegex =
/^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org/;
return !!googleCdnProxyRegex.test(win.location.origin);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you need the !!?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that being said I'll remove it

DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_EXPERIMENT,
], DFP_CANONICAL_FF_EXPERIMENT_NAME);
} else {
experimentName = DOUBLECLICK_A4A_EXPERIMENT_NAME;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could make this after beta check (as its not needed if it returns true)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/**
* @param {!Window} win
* @param {!Element} element
* @param {!Array} selectionBranches
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!Array

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confused, that's what I already have here...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow my comment didn't appear correctly... I meant to say that you can sub type this as an array of strings

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @param {!Element} element
* @param {!Array} selectionBranches
* @param {!string} experimentName}
* @return {?string} Experiment branch ID.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brand id or null if not selected

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -56,33 +58,32 @@ describe('doubleclick-a4a-config', () => {
});

describe('#doubleclickIsA4AEnabled', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am generally displeased that this class does not actually test any of the random selection code. The tests just force a selection and verify it returns the correct value. Given you're restructuring the class to ease testing, how would you feel about addressing this deficiency?

mockWin.location = parseUrl(
'https://cdn.ampproject.org/some/path/to/content.html');
it('should enable a4a when native crypto is supported', () => {
forceExperimentBranch(mockWin, DFP_CANONICAL_FF_EXPERIMENT_NAME,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, see my previous comment that we do not currently test experiment selection at all.

Copy link
Copy Markdown
Contributor

@keithwrightbos keithwrightbos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please file an issue to add more testing and make sure to test on local gulp against real sites to ensure its behaving properly.

/**
* @param {!Window} win
* @param {!Element} element
* @param {!Array} selectionBranches
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow my comment didn't appear correctly... I meant to say that you can sub type this as an array of strings

@bradfrizzell
Copy link
Copy Markdown
Contributor Author

Manually tested that we properly select in on CDN pages with and without experiment param, and tested that non-CDN pages now select in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants