From 1b512badd7e470aa892e103e5ed34c90893dd2a7 Mon Sep 17 00:00:00 2001 From: John Cowen Date: Tue, 21 Jan 2020 17:52:40 +0000 Subject: [PATCH] ui: Improve configuration/env/feature flag usage (also add build time year detection) (#7072) * Add new getEnvironment util/function * Use new-ish `env` function in all the places * Clean up ember env file, add year detection from commit date --- ui-v2/app/env.js | 64 +------ ui-v2/app/helpers/env.js | 13 +- ui-v2/app/initializers/client.js | 15 -- ui-v2/app/initializers/nspace.js | 4 +- .../app/instance-initializers/event-source.js | 8 +- ui-v2/app/instance-initializers/nspace.js | 6 +- ui-v2/app/instance-initializers/selection.js | 2 +- ui-v2/app/router.js | 8 +- ui-v2/app/routes/dc/acls.js | 6 +- ui-v2/app/services/client/http.js | 27 +-- .../app/services/repository/nspace/enabled.js | 4 +- ui-v2/app/utils/dom/event-source/index.js | 2 +- ui-v2/app/utils/get-environment.js | 100 +++++++++++ ui-v2/config/environment.js | 125 ++++++------- .../tests/unit/utils/get-environment-test.js | 165 ++++++++++++++++++ 15 files changed, 359 insertions(+), 190 deletions(-) delete mode 100644 ui-v2/app/initializers/client.js create mode 100644 ui-v2/app/utils/get-environment.js create mode 100644 ui-v2/tests/unit/utils/get-environment-test.js diff --git a/ui-v2/app/env.js b/ui-v2/app/env.js index 36a1ae26c..c26c39fce 100644 --- a/ui-v2/app/env.js +++ b/ui-v2/app/env.js @@ -1,61 +1,3 @@ -import _config from './config/environment'; -const doc = document; -const getDevEnvVars = function() { - return doc.cookie - .split(';') - .filter(item => item !== '') - .map(item => item.trim().split('=')); -}; -const getUserEnvVar = function(str) { - return window.localStorage.getItem(str); -}; -// TODO: Look at `services/client` for pulling -// HTTP headers in here so we can let things be controlled -// via HTTP proxies, for example turning off blocking -// queries if its a busy cluster -// const getOperatorEnvVars = function() {} - -// TODO: Not necessarily here but the entire app should -// use the `env` export not the `default` one -// but we might also change the name of this file, so wait for that first -export const env = function(str) { - let user = null; - switch (str) { - case 'CONSUL_UI_DISABLE_REALTIME': - case 'CONSUL_UI_DISABLE_ANCHOR_SELECTION': - case 'CONSUL_UI_REALTIME_RUNNER': - user = getUserEnvVar(str); - break; - } - // We use null here instead of an undefined check - // as localStorage will return null if not set - return user !== null ? user : _config[str]; -}; -export const config = function(key) { - let $; - switch (_config.environment) { - case 'development': - case 'staging': - case 'test': - $ = getDevEnvVars().reduce(function(prev, [key, value]) { - const val = !!JSON.parse(String(value).toLowerCase()); - switch (key) { - case 'CONSUL_ACLS_ENABLE': - prev['CONSUL_ACLS_ENABLED'] = val; - break; - case 'CONSUL_NSPACES_ENABLE': - prev['CONSUL_NSPACES_ENABLED'] = val; - break; - default: - prev[key] = value; - } - return prev; - }, {}); - if (typeof $[key] !== 'undefined') { - return $[key]; - } - break; - } - return _config[key]; -}; -export default env; +import config from './config/environment'; +import getEnvironment from './utils/get-environment'; +export const env = getEnvironment(config, window, document); diff --git a/ui-v2/app/helpers/env.js b/ui-v2/app/helpers/env.js index ae27da920..cfe0b3475 100644 --- a/ui-v2/app/helpers/env.js +++ b/ui-v2/app/helpers/env.js @@ -1,9 +1,6 @@ import { helper } from '@ember/component/helper'; -import { config } from 'consul-ui/env'; -// TODO: env actually uses config values not env values -// see `app/env` for the renaming TODO's also -export function env([name, def = ''], hash) { - return config(name) != null ? config(name) : def; -} - -export default helper(env); +import { env } from 'consul-ui/env'; +export default helper(function([name, def = ''], hash) { + const val = env(name); + return val != null ? val : def; +}); diff --git a/ui-v2/app/initializers/client.js b/ui-v2/app/initializers/client.js deleted file mode 100644 index 933290b9e..000000000 --- a/ui-v2/app/initializers/client.js +++ /dev/null @@ -1,15 +0,0 @@ -const scripts = document.getElementsByTagName('script'); -const current = scripts[scripts.length - 1]; - -export function initialize(application) { - const Client = application.resolveRegistration('service:client/http'); - Client.reopen({ - isCurrent: function(src) { - return current.src === src; - }, - }); -} - -export default { - initialize, -}; diff --git a/ui-v2/app/initializers/nspace.js b/ui-v2/app/initializers/nspace.js index 45a09b396..8586b3057 100644 --- a/ui-v2/app/initializers/nspace.js +++ b/ui-v2/app/initializers/nspace.js @@ -1,5 +1,5 @@ import Route from '@ember/routing/route'; -import { config } from 'consul-ui/env'; +import { env } from 'consul-ui/env'; import { routes } from 'consul-ui/router'; import flat from 'flat'; @@ -26,7 +26,7 @@ Route.reopen( return prev; }, {}) ); -if (config('CONSUL_NSPACES_ENABLED')) { +if (env('CONSUL_NSPACES_ENABLED')) { const dotRe = /\./g; initialize = function(container) { const all = Object.keys(flat(routes)) diff --git a/ui-v2/app/instance-initializers/event-source.js b/ui-v2/app/instance-initializers/event-source.js index 07b7f37b3..f354b9d12 100644 --- a/ui-v2/app/instance-initializers/event-source.js +++ b/ui-v2/app/instance-initializers/event-source.js @@ -1,11 +1,11 @@ -import env, { config } from 'consul-ui/env'; +import { env } from 'consul-ui/env'; export function initialize(container) { if (env('CONSUL_UI_DISABLE_REALTIME')) { return; } ['node', 'coordinate', 'session', 'service', 'proxy', 'discovery-chain'] - .concat(config('CONSUL_NSPACES_ENABLED') ? ['nspace/enabled'] : []) + .concat(env('CONSUL_NSPACES_ENABLED') ? ['nspace/enabled'] : []) .map(function(item) { // create repositories that return a promise resolving to an EventSource return { @@ -79,7 +79,7 @@ export function initialize(container) { }, ]) .concat( - config('CONSUL_NSPACES_ENABLED') + env('CONSUL_NSPACES_ENABLED') ? [ { route: 'dc/nspaces/index', @@ -104,7 +104,7 @@ export function initialize(container) { // but hardcode this for the moment if (typeof definition.route !== 'undefined') { container.inject(`route:${definition.route}`, name, `service:${servicePath}`); - if (config('CONSUL_NSPACES_ENABLED') && definition.route.startsWith('dc/')) { + if (env('CONSUL_NSPACES_ENABLED') && definition.route.startsWith('dc/')) { container.inject(`route:nspace/${definition.route}`, name, `service:${servicePath}`); } } else { diff --git a/ui-v2/app/instance-initializers/nspace.js b/ui-v2/app/instance-initializers/nspace.js index 72511faea..49c8cca1a 100644 --- a/ui-v2/app/instance-initializers/nspace.js +++ b/ui-v2/app/instance-initializers/nspace.js @@ -1,6 +1,6 @@ -import { config } from 'consul-ui/env'; +import { env } from 'consul-ui/env'; export function initialize(container) { - if (config('CONSUL_NSPACES_ENABLED')) { + if (env('CONSUL_NSPACES_ENABLED')) { ['dc', 'settings', 'dc.intentions.edit', 'dc.intentions.create'].forEach(function(item) { container.inject(`route:${item}`, 'nspacesRepo', 'service:repository/nspace/enabled'); container.inject(`route:nspace.${item}`, 'nspacesRepo', 'service:repository/nspace/enabled'); @@ -15,7 +15,7 @@ export function initialize(container) { // 1. Make it be about adding classes to the root dom node // 2. Make it be about config and things to do on initialization re: config // If we go with 1 then we need to move both this and the above nspaces class - if (config('CONSUL_ACLS_ENABLED')) { + if (env('CONSUL_ACLS_ENABLED')) { container .lookup('service:dom') .root() diff --git a/ui-v2/app/instance-initializers/selection.js b/ui-v2/app/instance-initializers/selection.js index 72b7e697c..d39c2a4aa 100644 --- a/ui-v2/app/instance-initializers/selection.js +++ b/ui-v2/app/instance-initializers/selection.js @@ -1,4 +1,4 @@ -import env from 'consul-ui/env'; +import { env } from 'consul-ui/env'; const SECONDARY_BUTTON = 2; const isSelecting = function(win = window) { diff --git a/ui-v2/app/router.js b/ui-v2/app/router.js index 995296164..eb38d7de5 100644 --- a/ui-v2/app/router.js +++ b/ui-v2/app/router.js @@ -1,10 +1,10 @@ import EmberRouter from '@ember/routing/router'; -import { config } from 'consul-ui/env'; +import { env } from 'consul-ui/env'; import walk from 'consul-ui/utils/routing/walk'; const Router = EmberRouter.extend({ - location: config('locationType'), - rootURL: config('rootURL'), + location: env('locationType'), + rootURL: env('rootURL'), }); export const routes = { // Our parent datacenter resource sets the namespace @@ -107,7 +107,7 @@ export const routes = { _options: { path: '/*path' }, }, }; -if (config('CONSUL_NSPACES_ENABLED')) { +if (env('CONSUL_NSPACES_ENABLED')) { routes.dc.nspaces = { _options: { path: '/namespaces' }, edit: { diff --git a/ui-v2/app/routes/dc/acls.js b/ui-v2/app/routes/dc/acls.js index f1e759ee4..fe78802ba 100644 --- a/ui-v2/app/routes/dc/acls.js +++ b/ui-v2/app/routes/dc/acls.js @@ -1,6 +1,6 @@ import Route from '@ember/routing/route'; import { get } from '@ember/object'; -import { config } from 'consul-ui/env'; +import { env } from 'consul-ui/env'; import { inject as service } from '@ember/service'; import WithBlockingActions from 'consul-ui/mixins/with-blocking-actions'; export default Route.extend(WithBlockingActions, { @@ -32,9 +32,9 @@ export default Route.extend(WithBlockingActions, { return false; }); } else { - // TODO: Ideally we wouldn't need to use config() at a route level + // TODO: Ideally we wouldn't need to use env() at a route level // transitionTo should probably remove it instead if NSPACES aren't enabled - if (config('CONSUL_NSPACES_ENABLED') && get(item, 'token.Namespace') !== nspace) { + if (env('CONSUL_NSPACES_ENABLED') && get(item, 'token.Namespace') !== nspace) { let routeName = this.router.currentRouteName; if (!routeName.startsWith('nspace')) { routeName = `nspace.${routeName}`; diff --git a/ui-v2/app/services/client/http.js b/ui-v2/app/services/client/http.js index 9de70b9c5..981f22999 100644 --- a/ui-v2/app/services/client/http.js +++ b/ui-v2/app/services/client/http.js @@ -3,6 +3,7 @@ import Service, { inject as service } from '@ember/service'; import { get, set } from '@ember/object'; import { Promise } from 'rsvp'; +import { env } from 'consul-ui/env'; import getObjectPool from 'consul-ui/utils/get-object-pool'; import Request from 'consul-ui/utils/http/request'; import createURL from 'consul-ui/utils/createURL'; @@ -41,31 +42,7 @@ export default Service.extend({ settings: service('settings'), init: function() { this._super(...arguments); - let protocol = 'http/1.1'; - try { - protocol = performance.getEntriesByType('resource').find(item => { - // isCurrent is added in initializers/client and is used - // to ensure we use the consul-ui.js src to sniff what the protocol - // is. Based on the assumption that whereever this script is it's - // likely to be the same as the xmlhttprequests - return item.initiatorType === 'script' && this.isCurrent(item.name); - }).nextHopProtocol; - } catch (e) { - // pass through - } - let maxConnections; - // http/2, http2+QUIC/39 and SPDY don't have connection limits - switch (true) { - case protocol.indexOf('h2') === 0: - case protocol.indexOf('hq') === 0: - case protocol.indexOf('spdy') === 0: - break; - default: - // generally 6 are available - // reserve 1 for traffic that we can't manage - maxConnections = 5; - break; - } + const maxConnections = env('CONSUL_HTTP_MAX_CONNECTIONS'); set(this, 'connections', getObjectPool(dispose, maxConnections)); if (typeof maxConnections !== 'undefined') { set(this, 'maxConnections', maxConnections); diff --git a/ui-v2/app/services/repository/nspace/enabled.js b/ui-v2/app/services/repository/nspace/enabled.js index 6e42f7c42..7a640b44a 100644 --- a/ui-v2/app/services/repository/nspace/enabled.js +++ b/ui-v2/app/services/repository/nspace/enabled.js @@ -1,6 +1,6 @@ import { inject as service } from '@ember/service'; import { get } from '@ember/object'; -import { config } from 'consul-ui/env'; +import { env } from 'consul-ui/env'; import RepositoryService from 'consul-ui/services/repository'; const modelName = 'nspace'; @@ -18,7 +18,7 @@ export default RepositoryService.extend({ return this.store.query(this.getModelName(), query); }, authorize: function(dc, nspace) { - if (!config('CONSUL_ACLS_ENABLED')) { + if (!env('CONSUL_ACLS_ENABLED')) { return Promise.resolve([ { Resource: 'operator', diff --git a/ui-v2/app/utils/dom/event-source/index.js b/ui-v2/app/utils/dom/event-source/index.js index 0a431ea59..f59556d6e 100644 --- a/ui-v2/app/utils/dom/event-source/index.js +++ b/ui-v2/app/utils/dom/event-source/index.js @@ -18,7 +18,7 @@ import StorageEventSourceFactory from 'consul-ui/utils/dom/event-source/storage' import EmberObject from '@ember/object'; import { task } from 'ember-concurrency'; -import env from 'consul-ui/env'; +import { env } from 'consul-ui/env'; let runner; switch (env('CONSUL_UI_REALTIME_RUNNER')) { diff --git a/ui-v2/app/utils/get-environment.js b/ui-v2/app/utils/get-environment.js new file mode 100644 index 000000000..962680d1c --- /dev/null +++ b/ui-v2/app/utils/get-environment.js @@ -0,0 +1,100 @@ +export default function(config = {}, win = window, doc = document) { + const dev = function() { + return doc.cookie + .split(';') + .filter(item => item !== '') + .map(item => item.trim().split('=')); + }; + const user = function(str) { + const item = win.localStorage.getItem(str); + return item === null ? undefined : item; + }; + const getCurrentResource = function(scripts) { + const current = scripts[scripts.length - 1]; + try { + return win.performance.getEntriesByType('resource').find(item => { + // current is based on the assumption that whereever this script is it's + // likely to be the same as the xmlhttprequests + return item.initiatorType === 'script' && current.src === item.name; + }); + } catch (e) { + return {}; + } + }; + const resource = getCurrentResource(doc.getElementsByTagName('script')); + + // TODO: Look to see if we can pull in HTTP headers here + // so we can let things be controlled via HTTP proxies, for example + // turning off blocking queries if its a busy cluster etc + const operator = function(str, env) { + let protocol; + switch (str) { + case 'CONSUL_HTTP_PROTOCOL': + return resource.nextHopProtocol || 'http/1.1'; + case 'CONSUL_HTTP_MAX_CONNECTIONS': + protocol = env('CONSUL_HTTP_PROTOCOL'); + // http/2, http2+QUIC/39 and SPDY don't have connection limits + switch (true) { + case protocol.indexOf('h2') === 0: + case protocol.indexOf('hq') === 0: + case protocol.indexOf('spdy') === 0: + // TODO: Change this to return -1 so we try to consistently + // return a value from env vars + return; + default: + // generally 6 are available + // reserve 1 for traffic that we can't manage + return 5; + } + } + }; + const ui = function(key) { + let $; + switch (config.environment) { + case 'development': + case 'staging': + case 'coverage': + case 'test': + $ = dev().reduce(function(prev, [key, value]) { + switch (key) { + case 'CONSUL_ACLS_ENABLE': + prev['CONSUL_ACLS_ENABLED'] = !!JSON.parse(String(value).toLowerCase()); + break; + case 'CONSUL_NSPACES_ENABLE': + prev['CONSUL_NSPACES_ENABLED'] = !!JSON.parse(String(value).toLowerCase()); + break; + default: + prev[key] = value; + } + return prev; + }, {}); + if (typeof $[key] !== 'undefined') { + return $[key]; + } + break; + } + return config[key]; + }; + return function env(str) { + switch (str) { + // All user providable values should start with CONSUL_UI + // We allow the user to set these ones via localStorage + // user value is preferred. + case 'CONSUL_UI_DISABLE_REALTIME': + case 'CONSUL_UI_DISABLE_ANCHOR_SELECTION': + // these are booleans cast things out + return !!JSON.parse(String(user(str) || 0).toLowerCase()) || ui(str); + case 'CONSUL_UI_REALTIME_RUNNER': + // these are strings + return user(str) || ui(str); + + case 'CONSUL_HTTP_PROTOCOL': + case 'CONSUL_HTTP_MAX_CONNECTIONS': + // We allow the operator to set these ones via various methods + // although UI developer config is preferred + return ui(str) || operator(str, env); + default: + return ui(str); + } + }; +} diff --git a/ui-v2/config/environment.js b/ui-v2/config/environment.js index a33bc69a4..2d00b4d02 100644 --- a/ui-v2/config/environment.js +++ b/ui-v2/config/environment.js @@ -2,8 +2,6 @@ const fs = require('fs'); const path = require('path'); module.exports = function(environment) { - const isDevLike = ['development', 'staging', 'test'].indexOf(environment) > -1; - const isProdLike = ['production', 'staging'].indexOf(environment) > -1; let ENV = { modulePrefix: 'consul-ui', environment, @@ -19,7 +17,6 @@ module.exports = function(environment) { Date: false, }, }, - APP: { // Here you can pass flags/options to your application instance // when it is created @@ -30,23 +27,33 @@ module.exports = function(environment) { }; // TODO: These should probably go onto APP ENV = Object.assign({}, ENV, { - // TODO: Let people alter this, as with anchor selection - CONSUL_UI_DISABLE_REALTIME: false, + CONSUL_UI_DISABLE_REALTIME: typeof process.env.CONSUL_UI_DISABLE_REALTIME !== 'undefined', CONSUL_UI_DISABLE_ANCHOR_SELECTION: typeof process.env.CONSUL_UI_DISABLE_ANCHOR_SELECTION !== 'undefined', - CONSUL_GIT_SHA: (function() { - if (process.env.CONSUL_GIT_SHA) { - return process.env.CONSUL_GIT_SHA; + CONSUL_COPYRIGHT_YEAR: (function(val) { + if (val) { + return val; + } + return require('child_process') + .execSync('git show -s --format=%ci HEAD') + .toString() + .trim() + .split('-') + .shift(); + })(process.env.CONSUL_COPYRIGHT_YEAR), + CONSUL_GIT_SHA: (function(val) { + if (val) { + return val; } return require('child_process') .execSync('git rev-parse --short HEAD') .toString() .trim(); - })(), - CONSUL_VERSION: (function() { - if (process.env.CONSUL_VERSION) { - return process.env.CONSUL_VERSION; + })(process.env.CONSUL_GIT_SHA), + CONSUL_VERSION: (function(val) { + if (val) { + return val; } // see /scripts/dist.sh:8 const version_go = `${path.dirname(path.dirname(__dirname))}/version/version.go`; @@ -58,72 +65,68 @@ module.exports = function(environment) { }) .trim() .split('"')[1]; - })(), - CONSUL_BINARY_TYPE: (function() { - if (process.env.CONSUL_BINARY_TYPE) { - return process.env.CONSUL_BINARY_TYPE; - } - return 'oss'; - })(), + })(process.env.CONSUL_VERSION), + CONSUL_BINARY_TYPE: process.env.CONSUL_BINARY_TYPE ? process.env.CONSUL_BINARY_TYPE : 'oss', CONSUL_ACLS_ENABLED: false, CONSUL_NSPACES_ENABLED: false, + CONSUL_HOME_URL: 'https://www.consul.io', CONSUL_DOCS_URL: 'https://www.consul.io/docs', CONSUL_DOCS_LEARN_URL: 'https://learn.hashicorp.com/consul', CONSUL_DOCS_API_URL: 'https://www.consul.io/api', CONSUL_COPYRIGHT_URL: 'https://www.hashicorp.com', - CONSUL_COPYRIGHT_YEAR: '2019', }); + const isDevLike = ['development', 'staging', 'test'].indexOf(environment) > -1; + const isProdLike = ['production', 'staging'].indexOf(environment) > -1; switch (true) { + case environment === 'test': + ENV = Object.assign({}, ENV, { + locationType: 'none', + CONSUL_ACLS_ENABLED: true, + '@hashicorp/ember-cli-api-double': { + 'auto-import': false, + enabled: true, + endpoints: ['/node_modules/@hashicorp/consul-api-double/v1'], + }, + APP: Object.assign({}, ENV.APP, { + LOG_ACTIVE_GENERATION: false, + LOG_VIEW_LOOKUPS: false, + + rootElement: '#ember-testing', + autoboot: false, + }), + }); + // passthrough + case environment === 'staging': + ENV = Object.assign({}, ENV, { + '@hashicorp/ember-cli-api-double': { + enabled: true, + endpoints: ['/node_modules/@hashicorp/consul-api-double/v1'], + }, + }); + // passthrough + case environment === 'production': + ENV = Object.assign({}, ENV, { + CONSUL_ACLS_ENABLED: '{{.ACLsEnabled}}', + CONSUL_NSPACES_ENABLED: + '{{ if .NamespacesEnabled }}{{.NamespacesEnabled}}{{ else }}false{{ end }}', + }); + // passthrough case isDevLike: ENV = Object.assign({}, ENV, { CONSUL_NSPACES_ENABLED: true, CONSUL_ACLS_ENABLED: true, + // 'APP': Object.assign({}, ENV.APP, { + // 'LOG_RESOLVER': true, + // 'LOG_ACTIVE_GENERATION': true, + // 'LOG_TRANSITIONS': true, + // 'LOG_TRANSITIONS_INTERNAL': true, + // 'LOG_VIEW_LOOKUPS': true, + // }) }); - // ENV.APP.LOG_RESOLVER = true; - // ENV.APP.LOG_ACTIVE_GENERATION = true; - // ENV.APP.LOG_TRANSITIONS = true; - // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; - // ENV.APP.LOG_VIEW_LOOKUPS = true; break; case isProdLike: break; } - // TODO: Move this to use switch once the production forking - // below has been uncommented (once ACLs and NSPACEs flags are passed through) - if (environment === 'test') { - // Testem prefers this... - ENV.locationType = 'none'; - - // keep test console output quieter - ENV.APP.LOG_ACTIVE_GENERATION = false; - ENV.APP.LOG_VIEW_LOOKUPS = false; - - ENV.APP.rootElement = '#ember-testing'; - ENV.APP.autoboot = false; - ENV['@hashicorp/ember-cli-api-double'] = { - 'auto-import': false, - enabled: true, - endpoints: ['/node_modules/@hashicorp/consul-api-double/v1'], - }; - } - if (environment === 'staging') { - ENV['@hashicorp/ember-cli-api-double'] = { - enabled: true, - endpoints: ['/node_modules/@hashicorp/consul-api-double/v1'], - }; - } - - if (environment === 'production') { - ENV = Object.assign( - {}, - ENV, - { - CONSUL_ACLS_ENABLED: '{{.ACLsEnabled}}', - CONSUL_NSPACES_ENABLED: '{{ if .NamespacesEnabled }}{{.NamespacesEnabled}}{{ else }}false{{ end }}' - } - ); - // here you can enable a production-specific feature - } return ENV; }; diff --git a/ui-v2/tests/unit/utils/get-environment-test.js b/ui-v2/tests/unit/utils/get-environment-test.js new file mode 100644 index 000000000..738d68af1 --- /dev/null +++ b/ui-v2/tests/unit/utils/get-environment-test.js @@ -0,0 +1,165 @@ +import getEnvironment from 'consul-ui/utils/get-environment'; +import { module, test } from 'qunit'; +const getEntriesByType = function(type) { + return [ + { + initiatorType: 'script', + name: '', + nextHopProtocol: 'spdy', + }, + ]; +}; +const getElementsByTagName = function(name) { + return [ + { + src: '', + }, + ]; +}; +const win = { + performance: { + getEntriesByType: getEntriesByType, + }, + localStorage: { + getItem: function(key) {}, + }, +}; +const doc = { + cookie: '', + getElementsByTagName: getElementsByTagName, +}; +module('Unit | Utility | getEnvironment', function() { + test('it returns a function', function(assert) { + const config = {}; + const env = getEnvironment(config, win, doc); + assert.ok(typeof env === 'function'); + }); + test('it returns the correct operator value', function(assert) { + const config = {}; + const env = getEnvironment(config, win, doc); + assert.equal(env('CONSUL_HTTP_PROTOCOL'), 'spdy'); + }); + test('it returns the correct operator value when set via config', function(assert) { + const config = { + CONSUL_HTTP_PROTOCOL: 'hq', + }; + const env = getEnvironment(config, win, doc); + assert.equal(env('CONSUL_HTTP_PROTOCOL'), 'hq'); + }); + test('it returns the correct max connections depending on protocol', function(assert) { + let config = { + CONSUL_HTTP_PROTOCOL: 'hq', + }; + let env = getEnvironment(config, win, doc); + assert.equal(env('CONSUL_HTTP_MAX_CONNECTIONS'), undefined); + config = { + CONSUL_HTTP_PROTOCOL: 'http/1.1', + }; + env = getEnvironment(config, win, doc); + assert.equal(env('CONSUL_HTTP_MAX_CONNECTIONS'), 5); + }); + test('it returns the correct max connections if performance.getEntriesByType is not available', function(assert) { + const config = {}; + let win = {}; + let env = getEnvironment(config, win, doc); + assert.equal(env('CONSUL_HTTP_MAX_CONNECTIONS'), 5); + win = { + performance: {}, + }; + env = getEnvironment(config, win, doc); + assert.equal(env('CONSUL_HTTP_MAX_CONNECTIONS'), 5); + }); + test('it returns the correct user value', function(assert) { + const config = {}; + let win = { + localStorage: { + getItem: function(key) { + return '1'; + }, + }, + }; + let env = getEnvironment(config, win, doc); + assert.ok(env('CONSUL_UI_DISABLE_REALTIME')); + win = { + localStorage: { + getItem: function(key) { + return '0'; + }, + }, + }; + env = getEnvironment(config, win, doc); + assert.notOk(env('CONSUL_UI_DISABLE_REALTIME')); + win = { + localStorage: { + getItem: function(key) { + return null; + }, + }, + }; + env = getEnvironment(config, win, doc); + assert.notOk(env('CONSUL_UI_DISABLE_REALTIME')); + }); + test('it returns the correct user value when set via config', function(assert) { + const config = { + CONSUL_UI_DISABLE_REALTIME: true, + }; + const env = getEnvironment(config, win, doc); + assert.ok(env('CONSUL_UI_DISABLE_REALTIME')); + }); + test('it returns the correct dev value (via cookies)', function(assert) { + let config = { + environment: 'test', + CONSUL_NSPACES_ENABLED: false, + }; + let doc = { + cookie: 'CONSUL_NSPACES_ENABLE=1', + getElementsByTagName: getElementsByTagName, + }; + let env = getEnvironment(config, win, doc); + assert.ok(env('CONSUL_NSPACES_ENABLED')); + config = { + environment: 'test', + CONSUL_NSPACES_ENABLED: true, + }; + doc = { + cookie: 'CONSUL_NSPACES_ENABLE=0', + getElementsByTagName: getElementsByTagName, + }; + env = getEnvironment(config, win, doc); + assert.notOk(env('CONSUL_NSPACES_ENABLED')); + }); + test('it returns the correct dev value when set via config', function(assert) { + let config = { + CONSUL_NSPACES_ENABLED: true, + }; + let env = getEnvironment(config, win, doc); + assert.ok(env('CONSUL_NSPACES_ENABLED')); + config = { + CONSUL_NSPACES_ENABLED: false, + }; + env = getEnvironment(config, win, doc); + assert.notOk(env('CONSUL_NSPACES_ENABLED')); + }); + test("it returns the correct dev value (ignoring cookies when the environment doesn't allow it)", function(assert) { + let config = { + environment: 'production', + CONSUL_NSPACES_ENABLED: false, + }; + let doc = { + cookie: 'CONSUL_NSPACES_ENABLE=1', + getElementsByTagName: getElementsByTagName, + }; + let env = getEnvironment(config, win, doc); + assert.notOk(env('CONSUL_NSPACES_ENABLED')); + config = { + environment: 'production', + CONSUL_NSPACES_ENABLED: true, + }; + doc = { + cookie: 'CONSUL_NSPACES_ENABLE=0', + getElementsByTagName: getElementsByTagName, + }; + env = getEnvironment(config, win, doc); + assert.ok(env('CONSUL_NSPACES_ENABLED')); + }); +});