Skip to content
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

🏗 Add specific RTV opt-in to experiments.html #26434

Merged
merged 10 commits into from
Jan 23, 2020
44 changes: 44 additions & 0 deletions tools/experiments/experiments.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@
min-width: 60px;
}

details {
border: solid 1px gray;
margin-top: 5px;
padding: 10px;
}

details summary {
color: gray;
cursor: pointer;
}

details[open] summary {
color: inherit;
}

#subdomain {
color: gray;
font-family: 'Courier New', Courier, monospace;
Expand Down Expand Up @@ -112,6 +127,21 @@
display: block;
}

#rtv {
border: solid 1px gray;
width: calc(100% - 150px);
padding: 10px;
}

#rtv-submit {
background: #aaa;
margin: 5px;
}

#rtv-submit[disabled] {
color: #777;
}

#redirect > input {
border: solid 1px gray;
width: calc(100% - 20px);
Expand Down Expand Up @@ -218,6 +248,20 @@ <h2>Release channels</h2>

<section class="content">
<table id="channels-table" border=1></table>
<details id="rtv-details">
<summary>Advanced</summary>
<p>
You can manually opt in to a previously released RTV using this form.
</p>
<p>
<em>Warning:</em> This is an advanced setting. It is intended for use while debugging AMP runtime code, and is
not meant to be used to publish AMP documents. To opt out of this setting, clear the RTV in the input field.
</p>
<div>
<input id="rtv" placeholder="E.g., 011912312359590" maxlength="15" type="text">
<button id="rtv-submit" disabled>opt-in</button>
danielrozenberg marked this conversation as resolved.
Show resolved Hide resolved
</div>
</detail>
</section>

<!-- Only displayed on top-level cdn.ampproject.org. -->
Expand Down
78 changes: 58 additions & 20 deletions tools/experiments/experiments.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ setReportError(reportError);
const COOKIE_MAX_AGE_DAYS = 180; // 6 month
const MS_PER_DAY = 24 * 60 * 60 * 1000;
const COOKIE_MAX_AGE_MS = COOKIE_MAX_AGE_DAYS * MS_PER_DAY;
const RTV_COOKIE_MAX_AGE_MS = MS_PER_DAY / 2;

const RTV_PATTERN = /^\d{15}$/;

/**
* @typedef {{
* id: string,
Expand All @@ -49,8 +53,9 @@ let ExperimentDef;
* interpreted by the server to deliver a different version of the AMP
* JS libraries.
*/
const CANARY_EXPERIMENT_ID = 'dev-channel';
const RC_EXPERIMENT_ID = 'rc-channel';
const EXPERIMENTAL_CHANNEL_ID = 'experimental-channel';
const BETA_CHANNEL_ID = 'beta-channel';
const RTV_CHANNEL_ID = 'rtv-channel';

/**
* The different states of the AMP_CANARY cookie.
Expand All @@ -65,15 +70,15 @@ const AMP_CANARY_COOKIE = {
const CHANNELS = [
// Experimental Channel
{
id: CANARY_EXPERIMENT_ID,
id: EXPERIMENTAL_CHANNEL_ID,
name: 'AMP Experimental Channel (more info)',
spec:
'https://github.com/ampproject/amphtml/blob/master/' +
'contributing/release-schedule.md#amp-experimental-and-beta-channels',
},
// Beta Channel
{
id: RC_EXPERIMENT_ID,
id: BETA_CHANNEL_ID,
name: 'AMP Beta Channel (more info)',
spec:
'https://github.com/ampproject/amphtml/blob/master/' +
Expand Down Expand Up @@ -138,6 +143,32 @@ function build() {
} else {
redirect.setAttribute('hidden', '');
}

const rtvInput = document.getElementById('rtv');
const rtvButton = document.getElementById('rtv-submit');
rtvInput.addEventListener('input', () => {
rtvButton.disabled = rtvInput.value && !RTV_PATTERN.test(rtvInput.value);
rtvButton.textContent = rtvInput.value ? 'opt-in' : 'opt-out';
});
rtvButton.addEventListener('click', () => {
if (!rtvInput.value) {
showConfirmation_(
'Do you really want to opt out of RTV?',
setAmpCanaryCookie_.bind(null, AMP_CANARY_COOKIE.DISABLED)
danielrozenberg marked this conversation as resolved.
Show resolved Hide resolved
);
} else if (RTV_PATTERN.test(rtvInput.value)) {
showConfirmation_(
`Do you really want to opt in to RTV ${rtvInput.value}?`,
setAmpCanaryCookie_.bind(null, rtvInput.value)
);
}
});

if (isExperimentOn_(RTV_CHANNEL_ID)) {
rtvInput.value = getCookie(window, 'AMP_CANARY');
rtvInput.dispatchEvent(new Event('input'));
document.getElementById('rtv-details').open = true;
danielrozenberg marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
Expand Down Expand Up @@ -237,24 +268,31 @@ function updateExperimentRow(experiment) {
* @return {boolean}
*/
function isExperimentOn_(id) {
if (id == CANARY_EXPERIMENT_ID) {
return getCookie(window, 'AMP_CANARY') == AMP_CANARY_COOKIE.CANARY;
} else if (id == RC_EXPERIMENT_ID) {
return getCookie(window, 'AMP_CANARY') == AMP_CANARY_COOKIE.RC;
switch (id) {
case EXPERIMENTAL_CHANNEL_ID:
return getCookie(window, 'AMP_CANARY') == AMP_CANARY_COOKIE.CANARY;
case BETA_CHANNEL_ID:
return getCookie(window, 'AMP_CANARY') == AMP_CANARY_COOKIE.RC;
case RTV_CHANNEL_ID:
return RTV_PATTERN.test(getCookie(window, 'AMP_CANARY'));
default:
return isExperimentOn(window, /*OK*/ id);
}
return isExperimentOn(window, /*OK*/ id);
}

/**
* Opts in to / out of the "canary" or "rc" runtime types by setting the
* AMP_CANARY cookie.
* @param {string} cookieState One of AMP_CANARY_COOKIE.{DISABLED|CANARY|RC}
* @param {string} cookieState One of AMP_CANARY_COOKIE.{DISABLED|CANARY|RC} or
* a 15-digit RTV.
*/
function setAmpCanaryCookie_(cookieState) {
const validUntil =
cookieState != AMP_CANARY_COOKIE.DISABLED
? Date.now() + COOKIE_MAX_AGE_MS
: 0;
let validUntil = 0;
if (RTV_PATTERN.test(cookieState)) {
validUntil = Date.now() + RTV_COOKIE_MAX_AGE_MS;
} else if (cookieState != AMP_CANARY_COOKIE.DISABLED) {
validUntil = Date.now() + COOKIE_MAX_AGE_MS;
danielrozenberg marked this conversation as resolved.
Show resolved Hide resolved
}
const cookieOptions = {
// Set explicit domain, so the cookie gets sent to sub domains.
domain: location.hostname,
Expand All @@ -279,17 +317,17 @@ function setAmpCanaryCookie_(cookieState) {
function toggleExperiment_(id, name, opt_on) {
const currentlyOn = isExperimentOn_(id);
const on = opt_on === undefined ? !currentlyOn : opt_on;
// Protect against click jacking.
// Protect against accidental choice.
const confirmMessage = on
? 'Do you really want to activate the AMP experiment'
: 'Do you really want to deactivate the AMP experiment';
? 'Do you really want to activate the AMP experiment?'
: 'Do you really want to deactivate the AMP experiment?';

showConfirmation_(`${confirmMessage}: "${name}"`, () => {
if (id == CANARY_EXPERIMENT_ID) {
if (id == EXPERIMENTAL_CHANNEL_ID) {
setAmpCanaryCookie_(
on ? AMP_CANARY_COOKIE.CANARY : AMP_CANARY_COOKIE.DISABLED
);
} else if (id == RC_EXPERIMENT_ID) {
} else if (id == BETA_CHANNEL_ID) {
setAmpCanaryCookie_(
on ? AMP_CANARY_COOKIE.RC : AMP_CANARY_COOKIE.DISABLED
);
Expand Down Expand Up @@ -348,7 +386,7 @@ function getAmpConfig() {
xhr.send(null);
return promise
.then(text => {
const match = text.match(/self\.AMP_CONFIG=([^;]+)/);
const match = text.match(/self\.AMP_CONFIG=(\{.+?\})/);
danielrozenberg marked this conversation as resolved.
Show resolved Hide resolved
if (!match) {
throw new Error("Can't find AMP_CONFIG in: " + text);
}
Expand Down