Start experiment to Add Fast Fetch support to canonical AMP pages for DoubleClick#11063
Start experiment to Add Fast Fetch support to canonical AMP pages for DoubleClick#11063keithwrightbos merged 7 commits intoampproject:masterfrom google:frizz-canonical-ff-support
Conversation
| return supportsNativeCrypto && | ||
| (googleCdnProxyRegex.test(win.location.origin) || getMode(win).localDev || | ||
| getMode(win).test); | ||
| return win.crypto && (win.crypto.subtle || win.crypto.webkitSubtle); |
There was a problem hiding this comment.
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.
| isTrafficEligible: () => true, | ||
| branches: [DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL_CONTROL, | ||
| DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL], | ||
| DOUBLECLICK_EXPERIMENT_FEATURE.HOLDBACK_INTERNAL, |
There was a problem hiding this comment.
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.
| return false; | ||
| let singleton; | ||
|
|
||
| export class DoubleclickA4aEligibility { |
There was a problem hiding this comment.
Make this visibleForTesting
| element.hasAttribute('useSameDomainRenderingUntilDeprecated') || | ||
| !isGoogleAdsA4AValidEnvironment(win)) { | ||
| return false; | ||
| let singleton; |
There was a problem hiding this comment.
Any reason you can't assign the singleton immediately and make const?
| dev().info(TAG, `beta forced a4a selection ${element}`); | ||
| return true; | ||
|
|
||
| supportsCrypto(win) { |
There was a problem hiding this comment.
Doc here and throughout
| } | ||
|
|
||
| isA4aEnabled(win, element) { | ||
| element = element; |
There was a problem hiding this comment.
wha? you're assigning it to itself?
There was a problem hiding this comment.
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} |
| experimentId = URL_EXPERIMENT_MAPPING[urlExperimentId]; | ||
| dev().info( | ||
| TAG, `url experiment selection ${urlExperimentId}: ${experimentId}.`); | ||
| return this.addAndForceExperiment(win, element, experimentId, [ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
return singleton.isA4AEnabled(win, element);
| /** @visibleForTesting */ | ||
| export class DoubleclickA4aEligibility { | ||
| constructor() { | ||
| return singleton; |
| DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_CONTROL, | ||
| DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_EXPERIMENT, | ||
| ], DFP_CANONICAL_FF_EXPERIMENT_NAME); | ||
| if (experimentId) { |
There was a problem hiding this comment.
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);
| DOUBLECLICK_EXPERIMENT_FEATURE.SFG_EXP_ID].includes(experimentId); | ||
| } | ||
|
|
||
| const singleton = new DoubleclickA4aEligibility(); |
| 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, |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
I'm surprised this works give you never pass instance to anything. I would have expected:
sandbox.stub(DoubleclickA4aEligibility.prototype, 'supportsCrypto').returns(false);
There was a problem hiding this comment.
It works because it's a singleton, but I can do it the other way if this way is unclear
ads/google/a4a/utils.js
Outdated
| const supportsNativeCrypto = win.crypto && | ||
| (win.crypto.subtle || win.crypto.webkitSubtle); | ||
| const googleCdnProxyRegex = | ||
| /^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org/; |
There was a problem hiding this comment.
Are we consisted about the domain cdn.amproject.org.foo.com? Seems like we should guard against that.
There was a problem hiding this comment.
^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org((\/.*)|($))+ would work, please check it though
| /** @const {string} */ | ||
| export const BETA_EXPERIMENT_ID = '2077831'; | ||
|
|
||
| /** @visibleForTesting */ |
There was a problem hiding this comment.
Combine in the same comment as description
| !isGoogleAdsA4AValidEnvironment(win)) { | ||
| return false; | ||
| export class DoubleclickA4aEligibility { | ||
| constructor() {} |
There was a problem hiding this comment.
are you sure you need an empty constructor?
| */ | ||
| isCdnProxy(win) { | ||
| const googleCdnProxyRegex = | ||
| /^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org/; |
There was a problem hiding this comment.
make sure if you tighten you do so here as well.
| isCdnProxy(win) { | ||
| const googleCdnProxyRegex = | ||
| /^https:\/\/([a-zA-Z0-9_-]+\.)?cdn\.ampproject\.org/; | ||
| return !!googleCdnProxyRegex.test(win.location.origin); |
There was a problem hiding this comment.
Are you sure you need the !!?
There was a problem hiding this comment.
that being said I'll remove it
| DOUBLECLICK_EXPERIMENT_FEATURE.CANONICAL_EXPERIMENT, | ||
| ], DFP_CANONICAL_FF_EXPERIMENT_NAME); | ||
| } else { | ||
| experimentName = DOUBLECLICK_A4A_EXPERIMENT_NAME; |
There was a problem hiding this comment.
could make this after beta check (as its not needed if it returns true)
| /** | ||
| * @param {!Window} win | ||
| * @param {!Element} element | ||
| * @param {!Array} selectionBranches |
There was a problem hiding this comment.
confused, that's what I already have here...
There was a problem hiding this comment.
Somehow my comment didn't appear correctly... I meant to say that you can sub type this as an array of strings
| * @param {!Element} element | ||
| * @param {!Array} selectionBranches | ||
| * @param {!string} experimentName} | ||
| * @return {?string} Experiment branch ID. |
There was a problem hiding this comment.
brand id or null if not selected
| @@ -56,33 +58,32 @@ describe('doubleclick-a4a-config', () => { | |||
| }); | |||
|
|
|||
| describe('#doubleclickIsA4AEnabled', () => { | |||
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
Agreed, see my previous comment that we do not currently test experiment selection at all.
keithwrightbos
left a comment
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Somehow my comment didn't appear correctly... I meant to say that you can sub type this as an array of strings
|
Manually tested that we properly select in on CDN pages with and without experiment param, and tested that non-CDN pages now select in. |

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