Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | /** |
| 6 | * @fileoverview Manages the current user's participation in experiments (e.g. |
| 7 | * phased rollouts). |
| 8 | * |
| 9 | * This file is an early prototype serving the needs of go/monorail-slo-v0. |
| 10 | * |
| 11 | * The more mature design is under discussion: |
| 12 | * http://doc/1rtYXq68WSlTNCzVJiSttLWF14CiK5sOlEef2JWAgheg |
| 13 | */ |
| 14 | |
| 15 | /** |
| 16 | * An Enum representing known expreriments. |
| 17 | * |
| 18 | * @typedef {string} Experiment |
| 19 | */ |
| 20 | |
| 21 | /** |
| 22 | * @type {Experiment} |
| 23 | */ |
| 24 | export const SLO_EXPERIMENT = 'slo'; |
| 25 | |
| 26 | const EXPERIMENT_QUERY_PARAM = 'e'; |
| 27 | |
| 28 | const DISABLED_STR = '-'; |
| 29 | |
| 30 | const _SLO_EXPERIMENT_USER_DISPLAY_NAMES = new Set([ |
| 31 | 'jessan@google.com', |
| 32 | ]); |
| 33 | |
| 34 | /** |
| 35 | * Checks whether the current user is in given experiment. |
| 36 | * |
| 37 | * @param {Experiment} experiment The experiment to check. |
| 38 | * @param {UserV0=} user The current user. Although any user can currently |
| 39 | * be passed in, we only intend to support checking if the current user is |
| 40 | * in the experiment. In the future the user parameter may be removed. |
| 41 | * @param {Object} queryParams The current query parameters, parsed by qs. |
| 42 | * We support a string like 'e=-exp1,-exp2...' for disabling experiments. |
| 43 | * |
| 44 | * We allow disabling so that a user in the fishfood group can work around |
| 45 | * any bugs or undesired behaviors the experiment may introduce for them. |
| 46 | * |
| 47 | * As of now, we don't allow enabling experiments by override params. |
| 48 | * We may not want access shared beyond the fishfood group (e.g. if it is a |
| 49 | * feature we are likely to change dramatically or take away). |
| 50 | * @return {boolean} Whether the experiment is enabled for the current user. |
| 51 | */ |
| 52 | export const isExperimentEnabled = (experiment, user, queryParams) => { |
| 53 | const experimentOverrides = parseExperimentParam( |
| 54 | queryParams[EXPERIMENT_QUERY_PARAM]); |
| 55 | if (experimentOverrides[experiment] === false) { |
| 56 | return false; |
| 57 | } |
| 58 | switch (experiment) { |
| 59 | case SLO_EXPERIMENT: |
| 60 | return !!user && |
| 61 | _SLO_EXPERIMENT_USER_DISPLAY_NAMES.has(user.displayName); |
| 62 | default: |
| 63 | throw Error('Unknown experiment provided'); |
| 64 | } |
| 65 | }; |
| 66 | |
| 67 | /** |
| 68 | * Parses a comma separated list of experiments from the query string. |
| 69 | * Experiment strings preceded by DISABLED_STR are overrode to be disabled, |
| 70 | * otherwise they are to be enabled. |
| 71 | * |
| 72 | * Does not do any validation of the experiment string provided. |
| 73 | * |
| 74 | * @param {string?} experimentParam comma separated experiements. |
| 75 | * @return {Object} Maps experiment name to whether enabled or |
| 76 | * disabled boolean. May include invalid experiment names. |
| 77 | */ |
| 78 | const parseExperimentParam = (experimentParam) => { |
| 79 | const experimentOverrides = {}; |
| 80 | if (experimentParam) { |
| 81 | for (const experimentOverride of experimentParam.split(',')) { |
| 82 | if (experimentOverride.startsWith(DISABLED_STR)) { |
| 83 | const experiment = experimentOverride.substr(DISABLED_STR.length); |
| 84 | experimentOverrides[experiment] = false; |
| 85 | } else { |
| 86 | experimentOverrides[experimentOverride] = true; |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | return experimentOverrides; |
| 91 | }; |