From 4be0f6c061c1fa71e68893657ffcdcd35341d5bd Mon Sep 17 00:00:00 2001 From: John Cowen Date: Fri, 7 Feb 2020 11:02:53 +0000 Subject: [PATCH 1/2] ui: Run 2 separate test runs oss and ent (#7214) * ui: Make API integration tests aware of CONSUL_NSPACES_ENABLED * ui: Allow passing CONSUL_NSPACES_ENABLED in via the cli in ember * ui: Add more makefile targets/package scripts to switch NSPACEs on/off * ui: Ensure all acceptance tests continue to pass with NSPACEs on/off This required a little tweaking of the dictionary, at some point page-navigation and some of these little tweaks will no longer be required * ui: Try running CI frontend tests in two parellel runs oss/ent * ui: Use correct make target, use different names for the reports --- .circleci/config.yml | 27 +++++++-- ui-v2/GNUmakefile | 29 ++++++++-- ui-v2/app/adapters/application.js | 1 + ui-v2/config/environment.js | 9 ++- ui-v2/node-tests/config/environment.js | 20 ++++++- ui-v2/package.json | 3 + .../dc/acls/policies/as-many/nspaces.feature | 1 + .../acceptance/dc/nspaces/create.feature | 29 +++++----- .../acceptance/dc/nspaces/delete.feature | 54 ++++++++++++++++++ .../tests/acceptance/dc/nspaces/index.feature | 1 + .../acceptance/dc/nspaces/manage.feature | 1 + .../acceptance/dc/nspaces/update.feature | 1 + .../dc/services/instances/proxy.feature | 44 ++++++++++++++- ui-v2/tests/acceptance/deleting.feature | 2 - ui-v2/tests/acceptance/token-header.feature | 4 +- ui-v2/tests/dictionary.js | 18 +++++- ui-v2/tests/helpers/yadda-annotations.js | 56 +++++++++++-------- ui-v2/tests/integration/adapters/kv-test.js | 16 ++++-- .../tests/integration/adapters/policy-test.js | 10 +++- ui-v2/tests/integration/adapters/role-test.js | 10 +++- .../integration/adapters/service-test.js | 8 ++- .../integration/adapters/session-test.js | 10 +++- .../tests/integration/adapters/token-test.js | 16 ++++-- 23 files changed, 289 insertions(+), 81 deletions(-) create mode 100644 ui-v2/tests/acceptance/dc/nspaces/delete.feature diff --git a/.circleci/config.yml b/.circleci/config.yml index faf1b6c5f..0566674ff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -491,12 +491,28 @@ jobs: - dist # run ember frontend tests - ember-test: + ember-test-oss: docker: - image: *EMBER_IMAGE environment: - EMBER_TEST_PARALLEL: true #enables test parallelization with ember-exam - EMBER_TEST_REPORT: test-results/report.xml #outputs test report for CircleCI test summary + EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary + steps: + - checkout + - restore_cache: + key: *YARN_CACHE_KEY + - attach_workspace: + at: ui-v2 + - run: + working_directory: ui-v2 + command: make test-oss-ci + - store_test_results: + path: ui-v2/test-results + # run ember frontend tests + ember-test-ent: + docker: + - image: *EMBER_IMAGE + environment: + EMBER_TEST_REPORT: test-results/report-ent.xml #outputs test report for CircleCI test summary steps: - checkout - restore_cache: @@ -682,6 +698,9 @@ workflows: - ember-build: requires: - frontend-cache - - ember-test: + - ember-test-oss: + requires: + - ember-build + - ember-test-ent: requires: - ember-build diff --git a/ui-v2/GNUmakefile b/ui-v2/GNUmakefile index ed8b59f1d..cfed057e4 100644 --- a/ui-v2/GNUmakefile +++ b/ui-v2/GNUmakefile @@ -35,20 +35,39 @@ start-consul: deps start-api: deps yarn run start:api +# testing + +# things with 'view' will open your browser for you +# otherwise its headless + +# oss is currently with namespace support disabled test: deps test-node yarn run test -test-ci: deps test-node - yarn run test:ci - test-view: deps test-node yarn run test:view +test-oss: deps test-node + yarn run test:oss + +test-oss-view: deps test-node + yarn run test:oss:view + +# these run from CI, both with and without namespaces +test-ci: deps test-node + yarn run test:ci + +test-oss-ci: deps test-node + yarn run test:oss:ci + +# these tests are only possible to run outside of ember +# and use node + tape for a test harness +test-node: + yarn run test:node + test-parallel: deps yarn run test:parallel -test-node: - yarn run test:node lint: deps yarn run lint:hbs && yarn run lint:js diff --git a/ui-v2/app/adapters/application.js b/ui-v2/app/adapters/application.js index d3fee2f27..b9cea8cf1 100644 --- a/ui-v2/app/adapters/application.js +++ b/ui-v2/app/adapters/application.js @@ -1,5 +1,6 @@ import Adapter from './http'; import { inject as service } from '@ember/service'; +// TODO: This should be changed to use env import config from 'consul-ui/config/environment'; export const DATACENTER_QUERY_PARAM = 'dc'; diff --git a/ui-v2/config/environment.js b/ui-v2/config/environment.js index cddc43620..6a11c7de6 100644 --- a/ui-v2/config/environment.js +++ b/ui-v2/config/environment.js @@ -1,7 +1,7 @@ 'use strict'; const fs = require('fs'); const path = require('path'); -module.exports = function(environment) { +module.exports = function(environment, $ = process.env) { let ENV = { modulePrefix: 'consul-ui', environment, @@ -83,7 +83,10 @@ module.exports = function(environment) { ENV = Object.assign({}, ENV, { locationType: 'none', CONSUL_NSPACES_TEST: true, - CONSUL_ACLS_ENABLED: true, + CONSUL_NSPACES_ENABLED: + typeof $['CONSUL_NSPACES_ENABLED'] !== 'undefined' + ? !!JSON.parse(String($['CONSUL_NSPACES_ENABLED']).toLowerCase()) + : true, '@hashicorp/ember-cli-api-double': { 'auto-import': false, enabled: true, @@ -100,6 +103,7 @@ module.exports = function(environment) { break; case environment === 'staging': ENV = Object.assign({}, ENV, { + CONSUL_NSPACES_ENABLED: true, '@hashicorp/ember-cli-api-double': { enabled: true, endpoints: ['/node_modules/@hashicorp/consul-api-double/v1'], @@ -117,7 +121,6 @@ module.exports = function(environment) { switch (true) { case isDevLike: ENV = Object.assign({}, ENV, { - CONSUL_NSPACES_ENABLED: true, CONSUL_ACLS_ENABLED: true, // 'APP': Object.assign({}, ENV.APP, { // 'LOG_RESOLVER': true, diff --git a/ui-v2/node-tests/config/environment.js b/ui-v2/node-tests/config/environment.js index 63d340b1d..0efc70e33 100644 --- a/ui-v2/node-tests/config/environment.js +++ b/ui-v2/node-tests/config/environment.js @@ -18,6 +18,15 @@ test( CONSUL_ACLS_ENABLED: true, CONSUL_NSPACES_ENABLED: true, }, + { + $: { + CONSUL_NSPACES_ENABLED: 0 + }, + environment: 'test', + CONSUL_BINARY_TYPE: 'oss', + CONSUL_ACLS_ENABLED: true, + CONSUL_NSPACES_ENABLED: false, + }, { environment: 'staging', CONSUL_BINARY_TYPE: 'oss', @@ -26,10 +35,17 @@ test( } ].forEach( function(item) { - const env = getEnvironment(item.environment); + const env = getEnvironment(item.environment, typeof item.$ !== 'undefined' ? item.$ : undefined); Object.keys(item).forEach( function(key) { - t.equal(env[key], item[key], `Expect ${key} to equal ${item[key]} in the ${item.environment} environment`); + if(key === '$') { + return; + } + t.equal( + env[key], + item[key], + `Expect ${key} to equal ${item[key]} in the ${item.environment} environment ${typeof item.$ !== 'undefined' ? `(with ${JSON.stringify(item.$)})` : ''}` + ); } ); } diff --git a/ui-v2/package.json b/ui-v2/package.json index 14cff9b31..e396be256 100644 --- a/ui-v2/package.json +++ b/ui-v2/package.json @@ -22,9 +22,12 @@ "start:consul": "ember serve --proxy=${CONSUL_HTTP_ADDR:-http://localhost:8500} --port=${EMBER_SERVE_PORT:-4200} --live-reload-port=${EMBER_LIVE_RELOAD_PORT:-7020}", "start:api": "api-double --dir ./node_modules/@hashicorp/consul-api-double", "test": "ember test --test-port=${EMBER_TEST_PORT:-7357}", + "test:oss": "CONSUL_NSPACES_ENABLED=0 ember test --test-port=${EMBER_TEST_PORT:-7357}", "test:ci": "ember test --test-port=${EMBER_TEST_PORT:-7357} --path dist --silent --reporter xunit", + "test:oss:ci": "CONSUL_NSPACES_ENABLED=0 ember test --test-port=${EMBER_TEST_PORT:-7357} --path dist --silent --reporter xunit", "test:parallel": "EMBER_EXAM_PARALLEL=true ember exam --split=4 --parallel", "test:view": "ember test --server --test-port=${EMBER_TEST_PORT:-7357}", + "test:oss:view": "CONSUL_NSPACES_ENABLED=0 ember test --server --test-port=${EMBER_TEST_PORT:-7357}", "test:node": "tape ./node-tests/**/*.js", "test:coverage": "COVERAGE=true ember test --test-port=${EMBER_TEST_PORT:-7357}", "test:view:coverage": "COVERAGE=true ember test --server --test-port=${EMBER_TEST_PORT:-7357}", diff --git a/ui-v2/tests/acceptance/dc/acls/policies/as-many/nspaces.feature b/ui-v2/tests/acceptance/dc/acls/policies/as-many/nspaces.feature index 882030af7..d0cd2dd73 100644 --- a/ui-v2/tests/acceptance/dc/acls/policies/as-many/nspaces.feature +++ b/ui-v2/tests/acceptance/dc/acls/policies/as-many/nspaces.feature @@ -1,3 +1,4 @@ +@onlyNamespaceable @setupApplicationTest Feature: dc / acls / policies / as many / nspaces: As many for nspaces Scenario: diff --git a/ui-v2/tests/acceptance/dc/nspaces/create.feature b/ui-v2/tests/acceptance/dc/nspaces/create.feature index a03f66dea..19d52e482 100644 --- a/ui-v2/tests/acceptance/dc/nspaces/create.feature +++ b/ui-v2/tests/acceptance/dc/nspaces/create.feature @@ -1,14 +1,15 @@ -@setupApplicationTest -Feature: dc / acls / nspaces / create - Scenario: - Given 1 datacenter model with the value "datacenter" - When I visit the nspace page for yaml - --- - dc: datacenter - --- - Then the url should be /datacenter/namespaces/create - And the title should be "New Namespace - Consul" - -@ignore - Scenario: Test we can create a Namespace - Then ok +@setupApplicationTest +@onlyNamespaceable +Feature: dc / acls / nspaces / create + Scenario: + Given 1 datacenter model with the value "datacenter" + When I visit the nspace page for yaml + --- + dc: datacenter + --- + Then the url should be /datacenter/namespaces/create + And the title should be "New Namespace - Consul" + +@ignore + Scenario: Test we can create a Namespace + Then ok diff --git a/ui-v2/tests/acceptance/dc/nspaces/delete.feature b/ui-v2/tests/acceptance/dc/nspaces/delete.feature new file mode 100644 index 000000000..5598a8d1b --- /dev/null +++ b/ui-v2/tests/acceptance/dc/nspaces/delete.feature @@ -0,0 +1,54 @@ +@setupApplicationTest +@onlyNamespaceable +Feature: dc / nspaces / delete: Deleting items with confirmations, success and error notifications + In order to delete items in consul + As a user + I should be able to delete items, get confirmation or a error notification that it has or has not been deleted + Background: + Given 1 datacenter model with the value "datacenter" + Scenario: Deleting a [Edit] model from the [Listing] listing page + Given 1 [Edit] model from json + --- + [Data] + --- + When I visit the [Listing] page for yaml + --- + dc: datacenter + --- + And I click actions on the [Listing] + And I click delete on the [Listing] + And I click confirmDelete on the [Listing] + Then a [Method] request was made to "[URL]" + And "[data-notification]" has the "notification-delete" class + And "[data-notification]" has the "success" class + Where: + -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + | Edit | Listing | Method | URL | Data | + | nspace | nspaces | DELETE | /v1/namespace/a-namespace | {"Name": "a-namespace"} | + -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Scenario: Deleting a [Model] from the [Model] detail page + When I visit the [Model] page for yaml + --- + dc: datacenter + [Slug] + --- + And I click delete + And I click confirmDelete + Then a [Method] request was made to "[URL]" + And "[data-notification]" has the "notification-delete" class + And "[data-notification]" has the "success" class + When I visit the [Model] page for yaml + --- + dc: datacenter + [Slug] + --- + Given the url "[URL]" responds with a 500 status + And I click delete + And I click confirmDelete + And "[data-notification]" has the "notification-delete" class + And "[data-notification]" has the "error" class + Where: + ----------------------------------------------------------------------------------------------------------------------------------------------------------- + | Model | Method | URL | Slug | + | nspace | DELETE | /v1/namespace/a-namespace | namespace: a-namespace | + ----------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/ui-v2/tests/acceptance/dc/nspaces/index.feature b/ui-v2/tests/acceptance/dc/nspaces/index.feature index 095baa36c..567bbc9ce 100644 --- a/ui-v2/tests/acceptance/dc/nspaces/index.feature +++ b/ui-v2/tests/acceptance/dc/nspaces/index.feature @@ -1,4 +1,5 @@ @setupApplicationTest +@onlyNamespaceable Feature: dc / nspaces / index: Nspaces List Background: Given settings from yaml diff --git a/ui-v2/tests/acceptance/dc/nspaces/manage.feature b/ui-v2/tests/acceptance/dc/nspaces/manage.feature index 368bc2e04..9df85c3d9 100644 --- a/ui-v2/tests/acceptance/dc/nspaces/manage.feature +++ b/ui-v2/tests/acceptance/dc/nspaces/manage.feature @@ -1,4 +1,5 @@ @setupApplicationTest +@onlyNamespaceable Feature: dc / nspaces / manage : Managing Namespaces Scenario: Given settings from yaml diff --git a/ui-v2/tests/acceptance/dc/nspaces/update.feature b/ui-v2/tests/acceptance/dc/nspaces/update.feature index d97915223..77bce8393 100644 --- a/ui-v2/tests/acceptance/dc/nspaces/update.feature +++ b/ui-v2/tests/acceptance/dc/nspaces/update.feature @@ -1,4 +1,5 @@ @setupApplicationTest +@onlyNamespaceable Feature: dc / nspaces / update: Nspace Update Background: Given 1 datacenter model with the value "datacenter" diff --git a/ui-v2/tests/acceptance/dc/services/instances/proxy.feature b/ui-v2/tests/acceptance/dc/services/instances/proxy.feature index 996382eca..68eb43c8c 100644 --- a/ui-v2/tests/acceptance/dc/services/instances/proxy.feature +++ b/ui-v2/tests/acceptance/dc/services/instances/proxy.feature @@ -1,5 +1,47 @@ @setupApplicationTest Feature: dc / services / instances / proxy: Show Proxy Service Instance + @onlyNamespaceable + Scenario: A Proxy Service instance with a namespace + Given 1 datacenter model with the value "dc1" + And 1 instance model from yaml + --- + - Service: + Kind: connect-proxy + Name: service-0-proxy + ID: service-0-proxy-with-id + Proxy: + DestinationServiceName: service-0 + Expose: + Checks: false + Paths: [] + Upstreams: + - DestinationType: service + DestinationName: service-1 + DestinationNamespace: default + LocalBindAddress: 127.0.0.1 + LocalBindPort: 1111 + - DestinationType: prepared_query + DestinationName: service-group + LocalBindAddress: 127.0.0.1 + LocalBindPort: 1112 + --- + When I visit the instance page for yaml + --- + dc: dc1 + service: service-0-proxy + node: node-0 + id: service-0-proxy-with-id + --- + + When I click upstreams on the tabs + And I see upstreamsIsSelected on the tabs + And I see 2 of the upstreams object + And I see name on the upstreams like yaml + --- + - service-1 default + - service-group + --- + @notNamespaceable Scenario: A Proxy Service instance with no exposed checks Given 1 datacenter model with the value "dc1" And 1 instance model from yaml @@ -44,7 +86,7 @@ Feature: dc / services / instances / proxy: Show Proxy Service Instance And I see 2 of the upstreams object And I see name on the upstreams like yaml --- - - service-1 default + - service-1 - service-group --- And I see type on the upstreams like yaml diff --git a/ui-v2/tests/acceptance/deleting.feature b/ui-v2/tests/acceptance/deleting.feature index 317ff6ac8..240fee6e5 100644 --- a/ui-v2/tests/acceptance/deleting.feature +++ b/ui-v2/tests/acceptance/deleting.feature @@ -26,7 +26,6 @@ Feature: deleting: Deleting items with confirmations, success and error notifica | kv | kvs | DELETE | /v1/kv/key-name?dc=datacenter&ns=@!namespace | ["key-name"] | | intention | intentions | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} | | token | tokens | DELETE | /v1/acl/token/001fda31-194e-4ff1-a5ec-589abf2cafd0?dc=datacenter&ns=@!namespace | {"AccessorID": "001fda31-194e-4ff1-a5ec-589abf2cafd0"} | - | nspace | nspaces | DELETE | /v1/namespace/a-namespace | {"Name": "a-namespace"} | # | acl | acls | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Scenario: Deleting a [Model] from the [Model] detail page @@ -56,7 +55,6 @@ Feature: deleting: Deleting items with confirmations, success and error notifica | kv | DELETE | /v1/kv/key-name?dc=datacenter&ns=@!namespace | kv: key-name | | intention | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca | | token | DELETE | /v1/acl/token/001fda31-194e-4ff1-a5ec-589abf2cafd0?dc=datacenter&ns=@!namespace | token: 001fda31-194e-4ff1-a5ec-589abf2cafd0 | - | nspace | DELETE | /v1/namespace/a-namespace | namespace: a-namespace | # | acl | PUT | /v1/acl/destroy/something?dc=datacenter | acl: something | ----------------------------------------------------------------------------------------------------------------------------------------------------------- @ignore diff --git a/ui-v2/tests/acceptance/token-header.feature b/ui-v2/tests/acceptance/token-header.feature index 8ab8857a6..00c40679a 100644 --- a/ui-v2/tests/acceptance/token-header.feature +++ b/ui-v2/tests/acceptance/token-header.feature @@ -8,7 +8,7 @@ Feature: token-header Given 1 datacenter model with the value "datacenter" When I visit the index page Then the url should be /datacenter/services - And a GET request was made to "/v1/namespaces" from yaml + And a GET request was made to "/v1/internal/ui/services?dc=datacenter&ns=@namespace" from yaml --- headers: X-Consul-Token: '' @@ -28,7 +28,7 @@ Feature: token-header And I submit When I visit the index page Then the url should be /datacenter/services - And a GET request was made to "/v1/namespaces" from yaml + And a GET request was made to "/v1/internal/ui/services?dc=datacenter&ns=@namespace" from yaml --- headers: X-Consul-Token: [Token] diff --git a/ui-v2/tests/dictionary.js b/ui-v2/tests/dictionary.js index 2462953ae..3a031810b 100644 --- a/ui-v2/tests/dictionary.js +++ b/ui-v2/tests/dictionary.js @@ -1,7 +1,8 @@ /* eslint no-control-regex: "off" */ import Yadda from 'yadda'; import YAML from 'js-yaml'; -export default function(nspace, dict = new Yadda.Dictionary()) { +import { env } from '../env'; +export default function(annotations, nspace, dict = new Yadda.Dictionary()) { dict .define('model', /(\w+)/, function(model, cb) { switch (model) { @@ -43,7 +44,13 @@ export default function(nspace, dict = new Yadda.Dictionary()) { .define('yaml', /([^\u0000]*)/, function(val, cb) { // sometimes we need to always force a namespace queryParam // mainly for DELETEs - val = val.replace(/ns=@!namespace/g, `ns=${nspace || 'default'}`); + if (env('CONSUL_NSPACES_ENABLED')) { + val = val.replace(/ns=@!namespace/g, `ns=${nspace || 'default'}`); + } else { + val = val.replace(/&ns=@!namespace/g, ''); + val = val.replace(/&ns=\*/g, ''); + val = val.replace(/- \/v1\/namespaces/g, ''); + } if (typeof nspace === 'undefined' || nspace === '') { val = val.replace(/Namespace: @namespace/g, '').replace(/&ns=@namespace/g, ''); } @@ -57,7 +64,12 @@ export default function(nspace, dict = new Yadda.Dictionary()) { .define('endpoint', /([^\u0000]*)/, function(val, cb) { // if is @namespace is !important, always replace with namespace // or if its undefined or empty then use default - val = val.replace(/ns=@!namespace/g, `ns=${nspace || 'default'}`); + if (env('CONSUL_NSPACES_ENABLED')) { + val = val.replace(/ns=@!namespace/g, `ns=${nspace || 'default'}`); + } else { + val = val.replace(/&ns=@!namespace/g, ''); + val = val.replace(/&ns=\*/g, ''); + } // for endpoints if namespace isn't specified it should // never add the ns= unless its !important... if (typeof nspace !== 'undefined' && nspace !== '') { diff --git a/ui-v2/tests/helpers/yadda-annotations.js b/ui-v2/tests/helpers/yadda-annotations.js index 8ad1cdd0e..b981db868 100644 --- a/ui-v2/tests/helpers/yadda-annotations.js +++ b/ui-v2/tests/helpers/yadda-annotations.js @@ -32,7 +32,7 @@ const runTest = function(context, libraries, steps, scenarioContext) { }; const checkAnnotations = function(annotations, isScenario) { annotations = { - namespaceable: env('CONSUL_NSPACES_TEST'), + namespaceable: env('CONSUL_NSPACES_ENABLED'), ...annotations, }; if (annotations.ignore) { @@ -41,36 +41,48 @@ const checkAnnotations = function(annotations, isScenario) { }; } if (isScenario) { - return function(scenario, feature, yadda, yaddaAnnotations, library) { - test(`Scenario: ${scenario.title}`, function(assert) { - const libraries = library.default({ - assert: assert, - library: Yadda.localisation.English.library(getDictionary()), - }); - const scenarioContext = { - ctx: {}, + if (env('CONSUL_NSPACES_ENABLED')) { + if (!annotations.notnamespaceable) { + return function(scenario, feature, yadda, yaddaAnnotations, library) { + ['', 'default', 'team-1', undefined].forEach(function(item) { + test(`Scenario: ${ + scenario.title + } with the ${item === '' ? 'empty' : typeof item === 'undefined' ? 'undefined' : item} namespace set`, function(assert) { + const libraries = library.default({ + assert: assert, + library: Yadda.localisation.English.library(getDictionary(annotations, item)), + }); + const scenarioContext = { + ctx: { + nspace: item, + }, + }; + const result = runTest(this, libraries, scenario.steps, scenarioContext); + return result; + }); + }); }; - return runTest(this, libraries, scenario.steps, scenarioContext); - }); - if (annotations.namespaceable && !annotations.notnamespaceable) { - ['', 'default', 'team-1', undefined].forEach(function(item) { - test(`Scenario: ${ - scenario.title - } with the ${item === '' ? 'empty' : typeof item === 'undefined' ? 'undefined' : item} namespace set`, function(assert) { + } else { + return function() {}; + } + } else { + if (!annotations.onlynamespaceable) { + return function(scenario, feature, yadda, yaddaAnnotations, library) { + test(`Scenario: ${scenario.title}`, function(assert) { const libraries = library.default({ assert: assert, - library: Yadda.localisation.English.library(getDictionary(item)), + library: Yadda.localisation.English.library(getDictionary(annotations)), }); const scenarioContext = { - ctx: { - nspace: item, - }, + ctx: {}, }; return runTest(this, libraries, scenario.steps, scenarioContext); }); - }); + }; + } else { + return function() {}; } - }; + } } }; export const setupFeature = function(featureAnnotations) { diff --git a/ui-v2/tests/integration/adapters/kv-test.js b/ui-v2/tests/integration/adapters/kv-test.js index b7ab6f0c6..38ef3a3ea 100644 --- a/ui-v2/tests/integration/adapters/kv-test.js +++ b/ui-v2/tests/integration/adapters/kv-test.js @@ -1,5 +1,9 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; module('Integration | Adapter | kv', function(hooks) { setupTest(hooks); const dc = 'dc-1'; @@ -18,7 +22,7 @@ module('Integration | Adapter | kv', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:kv'); @@ -32,13 +36,13 @@ module('Integration | Adapter | kv', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:kv'); const client = this.owner.lookup('service:client/http'); const expected = `PUT /v1/kv/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; let actual = adapter .requestForCreateRecord( @@ -60,7 +64,7 @@ module('Integration | Adapter | kv', function(hooks) { const client = this.owner.lookup('service:client/http'); const flags = 12; const expected = `PUT /v1/kv/${id}?dc=${dc}&flags=${flags}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; let actual = adapter .requestForUpdateRecord( @@ -82,7 +86,7 @@ module('Integration | Adapter | kv', function(hooks) { const adapter = this.owner.lookup('adapter:kv'); const client = this.owner.lookup('service:client/http'); const expected = `DELETE /v1/kv/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; let actual = adapter .requestForDeleteRecord( @@ -103,7 +107,7 @@ module('Integration | Adapter | kv', function(hooks) { const client = this.owner.lookup('service:client/http'); const folder = `${id}/`; const expected = `DELETE /v1/kv/${folder}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }&recurse`; let actual = adapter .requestForDeleteRecord( diff --git a/ui-v2/tests/integration/adapters/policy-test.js b/ui-v2/tests/integration/adapters/policy-test.js index ececf85a3..6dba91940 100644 --- a/ui-v2/tests/integration/adapters/policy-test.js +++ b/ui-v2/tests/integration/adapters/policy-test.js @@ -1,5 +1,9 @@ import { module, test, skip } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; module('Integration | Adapter | policy', function(hooks) { setupTest(hooks); skip('urlForTranslateRecord returns the correct url', function(assert) { @@ -24,7 +28,7 @@ module('Integration | Adapter | policy', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:policy'); @@ -38,7 +42,7 @@ module('Integration | Adapter | policy', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:policy'); @@ -79,7 +83,7 @@ module('Integration | Adapter | policy', function(hooks) { const adapter = this.owner.lookup('adapter:policy'); const client = this.owner.lookup('service:client/http'); const expected = `DELETE /v1/acl/policy/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; const actual = adapter .requestForDeleteRecord( diff --git a/ui-v2/tests/integration/adapters/role-test.js b/ui-v2/tests/integration/adapters/role-test.js index d4001d094..e8ff856c2 100644 --- a/ui-v2/tests/integration/adapters/role-test.js +++ b/ui-v2/tests/integration/adapters/role-test.js @@ -1,5 +1,9 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; module('Integration | Adapter | role', function(hooks) { setupTest(hooks); const dc = 'dc-1'; @@ -17,7 +21,7 @@ module('Integration | Adapter | role', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:role'); @@ -31,7 +35,7 @@ module('Integration | Adapter | role', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:role'); @@ -72,7 +76,7 @@ module('Integration | Adapter | role', function(hooks) { const adapter = this.owner.lookup('adapter:role'); const client = this.owner.lookup('service:client/http'); const expected = `DELETE /v1/acl/role/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; const actual = adapter .requestForDeleteRecord( diff --git a/ui-v2/tests/integration/adapters/service-test.js b/ui-v2/tests/integration/adapters/service-test.js index 5212cfe17..face13299 100644 --- a/ui-v2/tests/integration/adapters/service-test.js +++ b/ui-v2/tests/integration/adapters/service-test.js @@ -1,5 +1,9 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; module('Integration | Adapter | service', function(hooks) { setupTest(hooks); const dc = 'dc-1'; @@ -17,7 +21,7 @@ module('Integration | Adapter | service', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:service'); @@ -31,7 +35,7 @@ module('Integration | Adapter | service', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); }); test("requestForQueryRecord throws if you don't specify an id", function(assert) { diff --git a/ui-v2/tests/integration/adapters/session-test.js b/ui-v2/tests/integration/adapters/session-test.js index f72d2c755..f6cc57894 100644 --- a/ui-v2/tests/integration/adapters/session-test.js +++ b/ui-v2/tests/integration/adapters/session-test.js @@ -1,5 +1,9 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; module('Integration | Adapter | session', function(hooks) { setupTest(hooks); const dc = 'dc-1'; @@ -19,7 +23,7 @@ module('Integration | Adapter | session', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:session'); @@ -33,13 +37,13 @@ module('Integration | Adapter | session', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForDeleteRecord returns the correct url/method when the nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:session'); const client = this.owner.lookup('service:client/http'); const expected = `PUT /v1/session/destroy/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; const actual = adapter .requestForDeleteRecord( diff --git a/ui-v2/tests/integration/adapters/token-test.js b/ui-v2/tests/integration/adapters/token-test.js index 39295a5fb..5dd692e7e 100644 --- a/ui-v2/tests/integration/adapters/token-test.js +++ b/ui-v2/tests/integration/adapters/token-test.js @@ -1,5 +1,9 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; module('Integration | Adapter | token', function(hooks) { setupTest(hooks); const dc = 'dc-1'; @@ -17,7 +21,7 @@ module('Integration | Adapter | token', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQuery returns the correct url/method when a policy is specified when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:token'); @@ -31,7 +35,7 @@ module('Integration | Adapter | token', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQuery returns the correct url/method when a role is specified when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:token'); @@ -45,7 +49,7 @@ module('Integration | Adapter | token', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:token'); @@ -59,7 +63,7 @@ module('Integration | Adapter | token', function(hooks) { actual = actual.split('\n'); assert.equal(actual.shift().trim(), expected); actual = actual.join('\n').trim(); - assert.equal(actual, `${typeof nspace !== 'undefined' ? `ns=${nspace}` : ``}`); + assert.equal(actual, `${shouldHaveNspace(nspace) ? `ns=${nspace}` : ``}`); }); test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) { const adapter = this.owner.lookup('adapter:token'); @@ -119,7 +123,7 @@ module('Integration | Adapter | token', function(hooks) { const adapter = this.owner.lookup('adapter:token'); const client = this.owner.lookup('service:client/http'); const expected = `DELETE /v1/acl/token/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; const actual = adapter .requestForDeleteRecord( @@ -139,7 +143,7 @@ module('Integration | Adapter | token', function(hooks) { const adapter = this.owner.lookup('adapter:token'); const client = this.owner.lookup('service:client/http'); const expected = `PUT /v1/acl/token/${id}/clone?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` }`; const actual = adapter .requestForCloneRecord( From 5b7a48e273385cb106e008d08e3f20339caf36d2 Mon Sep 17 00:00:00 2001 From: John Cowen Date: Fri, 7 Feb 2020 15:50:50 +0000 Subject: [PATCH 2/2] ui: oss don't ever POST/PUT Namespaces when writing data (#7238) * ui: Ensure we use nonEmptySet everywhere where we add Namespace We missed a coupld of places where we use the noEmptySet function, which will only perform the set if the specified property is non-empty. Currently we aren't certain there is a place in OSS where a Namespace can make its way down via the API and endup being PUT/POSTed back out again when saved. If this did ever happen we would assume it would be the default namespace, but we add an extra check here to ensure we never PUT/POST the Namespace property if Namespaces are disabled. * ui: Add step/assertion for assert if a property is NOT set in the body * ui: Improve updated/create acc testing for policy/token/roles: Including making sure a Namespace property is never sent through if you are running without namespace support --- ui-v2/app/adapters/policy.js | 11 +++- ui-v2/app/adapters/role.js | 11 +++- ui-v2/app/adapters/token.js | 11 +++- .../dc/acls/policies/create.feature | 65 +++++++++++++++---- .../dc/acls/policies/update.feature | 15 +++++ .../acceptance/dc/acls/roles/create.feature | 65 +++++++++++++++---- .../acceptance/dc/acls/roles/update.feature | 15 +++++ .../acceptance/dc/acls/tokens/create.feature | 60 +++++++++++++---- .../acceptance/dc/acls/tokens/update.feature | 15 +++++ ui-v2/tests/steps/assertions/http.js | 18 +++++ 10 files changed, 238 insertions(+), 48 deletions(-) diff --git a/ui-v2/app/adapters/policy.js b/ui-v2/app/adapters/policy.js index 628db43b4..7f6070e43 100644 --- a/ui-v2/app/adapters/policy.js +++ b/ui-v2/app/adapters/policy.js @@ -4,8 +4,15 @@ import { SLUG_KEY } from 'consul-ui/models/policy'; import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc'; import { NSPACE_KEY } from 'consul-ui/models/nspace'; +import { env } from 'consul-ui/env'; import nonEmptySet from 'consul-ui/utils/non-empty-set'; -const Namespace = nonEmptySet('Namespace'); + +let Namespace; +if (env('CONSUL_NSPACES_ENABLED')) { + Namespace = nonEmptySet('Namespace'); +} else { + Namespace = () => ({}); +} // TODO: Update to use this.formatDatacenter() export default Adapter.extend({ @@ -60,7 +67,7 @@ export default Adapter.extend({ Description: serialized.Description, Rules: serialized.Rules, Datacenters: serialized.Datacenters, - Namespace: serialized.Namespace, + ...Namespace(serialized.Namespace), }} `; }, diff --git a/ui-v2/app/adapters/role.js b/ui-v2/app/adapters/role.js index 6b796ef3f..5b7a1f46e 100644 --- a/ui-v2/app/adapters/role.js +++ b/ui-v2/app/adapters/role.js @@ -3,9 +3,16 @@ import Adapter from './application'; import { SLUG_KEY } from 'consul-ui/models/role'; import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc'; import { NSPACE_KEY } from 'consul-ui/models/nspace'; + +import { env } from 'consul-ui/env'; import nonEmptySet from 'consul-ui/utils/non-empty-set'; -const Namespace = nonEmptySet('Namespace'); +let Namespace; +if (env('CONSUL_NSPACES_ENABLED')) { + Namespace = nonEmptySet('Namespace'); +} else { + Namespace = () => ({}); +} // TODO: Update to use this.formatDatacenter() export default Adapter.extend({ requestForQuery: function(request, { dc, ns, index, id }) { @@ -57,9 +64,9 @@ export default Adapter.extend({ ${{ Name: serialized.Name, Description: serialized.Description, - Namespace: serialized.Namespace, Policies: serialized.Policies, ServiceIdentities: serialized.ServiceIdentities, + ...Namespace(serialized.Namespace), }} `; }, diff --git a/ui-v2/app/adapters/token.js b/ui-v2/app/adapters/token.js index 250a4dc5c..cc1f8d29c 100644 --- a/ui-v2/app/adapters/token.js +++ b/ui-v2/app/adapters/token.js @@ -4,9 +4,16 @@ import { inject as service } from '@ember/service'; import { SLUG_KEY } from 'consul-ui/models/token'; import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc'; import { NSPACE_KEY } from 'consul-ui/models/nspace'; + +import { env } from 'consul-ui/env'; import nonEmptySet from 'consul-ui/utils/non-empty-set'; -const Namespace = nonEmptySet('Namespace'); +let Namespace; +if (env('CONSUL_NSPACES_ENABLED')) { + Namespace = nonEmptySet('Namespace'); +} else { + Namespace = () => ({}); +} // TODO: Update to use this.formatDatacenter() export default Adapter.extend({ store: service('store'), @@ -74,11 +81,11 @@ export default Adapter.extend({ ${{ Description: serialized.Description, - Namespace: serialized.Namespace, Policies: serialized.Policies, Roles: serialized.Roles, ServiceIdentities: serialized.ServiceIdentities, Local: serialized.Local, + ...Namespace(serialized.Namespace), }} `; }, diff --git a/ui-v2/tests/acceptance/dc/acls/policies/create.feature b/ui-v2/tests/acceptance/dc/acls/policies/create.feature index 24cd49392..256bb4a8d 100644 --- a/ui-v2/tests/acceptance/dc/acls/policies/create.feature +++ b/ui-v2/tests/acceptance/dc/acls/policies/create.feature @@ -1,14 +1,51 @@ -@setupApplicationTest -Feature: dc / acls / policies / create - Scenario: - Given 1 datacenter model with the value "datacenter" - When I visit the policy page for yaml - --- - dc: datacenter - --- - Then the url should be /datacenter/acls/policies/create - And the title should be "New Policy - Consul" - -@ignore - Scenario: Test we can create a ACLs Policy - Then ok +@setupApplicationTest +Feature: dc / acls / policies / create + Background: + Given 1 datacenter model with the value "datacenter" + When I visit the policy page for yaml + --- + dc: datacenter + --- + Scenario: Visiting the page without error and the title is correct + Then the url should be /datacenter/acls/policies/create + And the title should be "New Policy - Consul" + + Scenario: Creating a simple ACL policy with description [Description] + Then I fill in the policy form with yaml + --- + Name: my-policy + Description: [Description] + --- + And I submit + Then a PUT request was made to "/v1/acl/policy?dc=datacenter" from yaml + --- + body: + Name: my-policy + Namespace: @namespace + Description: [Description] + --- + Then the url should be /datacenter/acls/policies + And "[data-notification]" has the "notification-create" class + And "[data-notification]" has the "success" class + Where: + --------------------------- + | Description | + | description | + | description with spaces | + --------------------------- + + @notNamespaceable + Scenario: Creating a simple ACL policy when Namespaces are disabled does not send Namespace + Then I fill in the policy form with yaml + --- + Name: my-policy + Description: Description + --- + And I submit + Then a PUT request was made to "/v1/acl/policy?dc=datacenter" without properties from yaml + --- + - Namespace + --- + Then the url should be /datacenter/acls/policies + And "[data-notification]" has the "notification-create" class + And "[data-notification]" has the "success" class diff --git a/ui-v2/tests/acceptance/dc/acls/policies/update.feature b/ui-v2/tests/acceptance/dc/acls/policies/update.feature index 22dc67d57..129a2116e 100644 --- a/ui-v2/tests/acceptance/dc/acls/policies/update.feature +++ b/ui-v2/tests/acceptance/dc/acls/policies/update.feature @@ -53,3 +53,18 @@ Feature: dc / acls / policies / update: ACL Policy Update Then the url should be /datacenter/acls/policies/policy-id Then "[data-notification]" has the "notification-update" class And "[data-notification]" has the "error" class + + @notNamespaceable + Scenario: Updating a simple ACL policy when Namespaces are disabled does not send Namespace + Then I fill in the policy form with yaml + --- + Description: Description + --- + And I submit + Then a PUT request was made to "/v1/acl/policy/policy-id?dc=datacenter" without properties from yaml + --- + - Namespace + --- + Then the url should be /datacenter/acls/policies + And "[data-notification]" has the "notification-update" class + And "[data-notification]" has the "success" class diff --git a/ui-v2/tests/acceptance/dc/acls/roles/create.feature b/ui-v2/tests/acceptance/dc/acls/roles/create.feature index cd46b02ec..ef3c109f1 100644 --- a/ui-v2/tests/acceptance/dc/acls/roles/create.feature +++ b/ui-v2/tests/acceptance/dc/acls/roles/create.feature @@ -1,14 +1,51 @@ -@setupApplicationTest -Feature: dc / acls / roles / create - Scenario: - Given 1 datacenter model with the value "datacenter" - When I visit the role page for yaml - --- - dc: datacenter - --- - Then the url should be /datacenter/acls/roles/create - And the title should be "New Role - Consul" - -@ignore - Scenario: Test we can create a ACLs role - Then ok +@setupApplicationTest +Feature: dc / acls / roles / create + Background: + Given 1 datacenter model with the value "datacenter" + When I visit the role page for yaml + --- + dc: datacenter + --- + + Scenario: Visiting the page without error and the title is correct + Then the url should be /datacenter/acls/roles/create + And the title should be "New Role - Consul" + Scenario: Creating a simple ACL role with description [Description] + Then I fill in the role form with yaml + --- + Name: my-role + Description: [Description] + --- + And I submit + Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml + --- + body: + Namespace: @namespace + Name: my-role + Description: [Description] + --- + Then the url should be /datacenter/acls/roles + And "[data-notification]" has the "notification-create" class + And "[data-notification]" has the "success" class + Where: + --------------------------- + | Description | + | description | + | description with spaces | + --------------------------- + @notNamespaceable + Scenario: Creating a simple ACL role when Namespaces are disabled does not send Namespace + Then I fill in the role form with yaml + --- + Name: my-role + Description: Description + --- + And I submit + Then a PUT request was made to "/v1/acl/role?dc=datacenter" without properties from yaml + --- + - Namespace + --- + Then the url should be /datacenter/acls/roles + And "[data-notification]" has the "notification-create" class + And "[data-notification]" has the "success" class + diff --git a/ui-v2/tests/acceptance/dc/acls/roles/update.feature b/ui-v2/tests/acceptance/dc/acls/roles/update.feature index f039b8551..2f82852c1 100644 --- a/ui-v2/tests/acceptance/dc/acls/roles/update.feature +++ b/ui-v2/tests/acceptance/dc/acls/roles/update.feature @@ -45,3 +45,18 @@ Feature: dc / acls / roles / update: ACL Role Update Then the url should be /datacenter/acls/roles/role-id Then "[data-notification]" has the "notification-update" class And "[data-notification]" has the "error" class + + @notNamespaceable + Scenario: Updating a simple ACL role when Namespaces are disabled does not send Namespace + Then I fill in the role form with yaml + --- + Description: Description + --- + And I submit + Then a PUT request was made to "/v1/acl/role/role-id?dc=datacenter" without properties from yaml + --- + - Namespace + --- + Then the url should be /datacenter/acls/roles + And "[data-notification]" has the "notification-update" class + And "[data-notification]" has the "success" class diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/create.feature b/ui-v2/tests/acceptance/dc/acls/tokens/create.feature index a536224e1..654206310 100644 --- a/ui-v2/tests/acceptance/dc/acls/tokens/create.feature +++ b/ui-v2/tests/acceptance/dc/acls/tokens/create.feature @@ -1,14 +1,46 @@ -@setupApplicationTest -Feature: dc / acls / tokens / create - Scenario: - Given 1 datacenter model with the value "datacenter" - When I visit the token page for yaml - --- - dc: datacenter - --- - Then the url should be /datacenter/acls/tokens/create - And the title should be "New Token - Consul" - -@ignore - Scenario: Test we can create a ACLs Token - Then ok +@setupApplicationTest +Feature: dc / acls / tokens / create + Background: + Given 1 datacenter model with the value "datacenter" + When I visit the token page for yaml + --- + dc: datacenter + --- + Scenario: Visiting the page without error and the title is correct + Then the url should be /datacenter/acls/tokens/create + And the title should be "New Token - Consul" + Scenario: Creating a simple ACL token with description [Description] + Then I fill in with yaml + --- + Description: [Description] + --- + And I submit + Then a PUT request was made to "/v1/acl/token?dc=datacenter" from yaml + --- + body: + Namespace: @namespace + Description: [Description] + --- + Then the url should be /datacenter/acls/tokens + And "[data-notification]" has the "notification-create" class + And "[data-notification]" has the "success" class + Where: + --------------------------- + | Description | + | description | + | description with spaces | + --------------------------- + @notNamespaceable + Scenario: Creating a simple ACL token when Namespaces are disabled does not send Namespace + Then I fill in with yaml + --- + Description: Description + --- + And I submit + Then a PUT request was made to "/v1/acl/token?dc=datacenter" without properties from yaml + --- + - Namespace + --- + Then the url should be /datacenter/acls/tokens + And "[data-notification]" has the "notification-create" class + And "[data-notification]" has the "success" class diff --git a/ui-v2/tests/acceptance/dc/acls/tokens/update.feature b/ui-v2/tests/acceptance/dc/acls/tokens/update.feature index 44106f0f0..c3b8e3d77 100644 --- a/ui-v2/tests/acceptance/dc/acls/tokens/update.feature +++ b/ui-v2/tests/acceptance/dc/acls/tokens/update.feature @@ -41,3 +41,18 @@ Feature: dc / acls / tokens / update: ACL Token Update Then the url should be /datacenter/acls/tokens/key Then "[data-notification]" has the "notification-update" class And "[data-notification]" has the "error" class + + @notNamespaceable + Scenario: Updating a simple ACL token when Namespaces are disabled does not send Namespace + Then I fill in with yaml + --- + Description: Description + --- + And I submit + Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" without properties from yaml + --- + - Namespace + --- + Then the url should be /datacenter/acls/tokens + And "[data-notification]" has the "notification-update" class + And "[data-notification]" has the "success" class diff --git a/ui-v2/tests/steps/assertions/http.js b/ui-v2/tests/steps/assertions/http.js index 21ee6c3d9..511e8fe96 100644 --- a/ui-v2/tests/steps/assertions/http.js +++ b/ui-v2/tests/steps/assertions/http.js @@ -81,5 +81,23 @@ export default function(scenario, assert, lastNthRequest) { )}, ${key} was ${JSON.stringify(headers[key])}` ); }); + }) + .then('a $method request was made to "$endpoint" without properties from yaml\n$yaml', function( + method, + url, + properties + ) { + const requests = lastNthRequest(null, method); + const request = requests.find(function(item) { + return method === item.method && url === item.url; + }); + const body = JSON.parse(request.requestBody); + properties.forEach(function(key, i, arr) { + assert.equal( + typeof body[key], + 'undefined', + `Expected payload to not have a ${key} property` + ); + }); }); }