Merge pull request #7241 from hashicorp/ui-staging

UI Release Merge (ui-staging merge)
This commit is contained in:
John Cowen 2020-02-07 16:07:05 +00:00 committed by GitHub
commit ee956a4cfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 527 additions and 129 deletions

View File

@ -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

View File

@ -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

View File

@ -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';

View File

@ -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),
}}
`;
},

View File

@ -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),
}}
`;
},

View File

@ -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),
}}
`;
},

View File

@ -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,

View File

@ -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.$)})` : ''}`
);
}
);
}

View File

@ -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}",

View File

@ -1,3 +1,4 @@
@onlyNamespaceable
@setupApplicationTest
Feature: dc / acls / policies / as many / nspaces: As many for nspaces
Scenario:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 |
-----------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -1,4 +1,5 @@
@setupApplicationTest
@onlyNamespaceable
Feature: dc / nspaces / index: Nspaces List
Background:
Given settings from yaml

View File

@ -1,4 +1,5 @@
@setupApplicationTest
@onlyNamespaceable
Feature: dc / nspaces / manage : Managing Namespaces
Scenario:
Given settings from yaml

View File

@ -1,4 +1,5 @@
@setupApplicationTest
@onlyNamespaceable
Feature: dc / nspaces / update: Nspace Update
Background:
Given 1 datacenter model with the value "datacenter"

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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 !== '') {

View File

@ -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) {

View File

@ -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(

View File

@ -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(

View File

@ -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(

View File

@ -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) {

View File

@ -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(

View File

@ -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(

View File

@ -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`
);
});
});
}