mirror of https://github.com/status-im/consul.git
ui: Acceptance test improvements to prepare for more NS tests (#6980)
* ui: Acceptance test improvements to prepare for more NS tests * ui: Namespace acceptance testing (#7005) * Update api-double and consul-api-double for http.body * Adds places where we missed passing the nspace through * Hardcode nspace CRUD to use the default nspace for policies and roles * Alter test helpers to allow us to control nspaces from the outside * Amends to allow tests to account for namespace, move ns from queryParam 1. We decided to move how we pass the namespace value through to the backend when performing write actions (create, update). Previoulsy we were using the queryParam although using the post body is the preferred method to send the Namespace details through to the backend. 2. Other various amends to take into account testing across multiple namespaced scenarios * Enable nspace testing by default * Remove last few occurances of old style http assertions We had informally 'deprecated' our old style of http assertions that relied on the order of http calls (even though that order was not important for the assertion). Following on from our namespace work we removed the majority of the old occrances of these old style assertions. This commit removes the remaining few, and also then cleans up the assertions/http.js file to only include the ones we are using. This reduces our available step count further and prevents any confusion over the usage of the old types and the new types. * ui: Namespace CRUD acceptance tests (#7016) * Upgrade consul-api-double * Add all the things required for testing: 1. edit and index page objects 2. enable CONSUL_NSPACE_COUNT cookie setting 3. enable mutating HTTP response bodies based on URL * Add acceptance test for nspace edit/delete/list and searching
This commit is contained in:
parent
b836a772fc
commit
327aac9fe9
|
@ -4,6 +4,9 @@ import { SLUG_KEY } from 'consul-ui/models/policy';
|
||||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||||
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
||||||
|
|
||||||
|
import nonEmptySet from 'consul-ui/utils/non-empty-set';
|
||||||
|
const Namespace = nonEmptySet('Namespace');
|
||||||
|
|
||||||
// TODO: Update to use this.formatDatacenter()
|
// TODO: Update to use this.formatDatacenter()
|
||||||
export default Adapter.extend({
|
export default Adapter.extend({
|
||||||
requestForQuery: function(request, { dc, ns, index, id }) {
|
requestForQuery: function(request, { dc, ns, index, id }) {
|
||||||
|
@ -32,7 +35,6 @@ export default Adapter.extend({
|
||||||
requestForCreateRecord: function(request, serialized, data) {
|
requestForCreateRecord: function(request, serialized, data) {
|
||||||
const params = {
|
const params = {
|
||||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||||
...this.formatNspace(data[NSPACE_KEY]),
|
|
||||||
};
|
};
|
||||||
return request`
|
return request`
|
||||||
PUT /v1/acl/policy?${params}
|
PUT /v1/acl/policy?${params}
|
||||||
|
@ -42,13 +44,13 @@ export default Adapter.extend({
|
||||||
Description: serialized.Description,
|
Description: serialized.Description,
|
||||||
Rules: serialized.Rules,
|
Rules: serialized.Rules,
|
||||||
Datacenters: serialized.Datacenters,
|
Datacenters: serialized.Datacenters,
|
||||||
|
...Namespace(serialized.Namespace),
|
||||||
}}
|
}}
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
requestForUpdateRecord: function(request, serialized, data) {
|
requestForUpdateRecord: function(request, serialized, data) {
|
||||||
const params = {
|
const params = {
|
||||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||||
...this.formatNspace(data[NSPACE_KEY]),
|
|
||||||
};
|
};
|
||||||
return request`
|
return request`
|
||||||
PUT /v1/acl/policy/${data[SLUG_KEY]}?${params}
|
PUT /v1/acl/policy/${data[SLUG_KEY]}?${params}
|
||||||
|
@ -58,6 +60,7 @@ export default Adapter.extend({
|
||||||
Description: serialized.Description,
|
Description: serialized.Description,
|
||||||
Rules: serialized.Rules,
|
Rules: serialized.Rules,
|
||||||
Datacenters: serialized.Datacenters,
|
Datacenters: serialized.Datacenters,
|
||||||
|
Namespace: serialized.Namespace,
|
||||||
}}
|
}}
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,9 @@ import Adapter from './application';
|
||||||
import { SLUG_KEY } from 'consul-ui/models/role';
|
import { SLUG_KEY } from 'consul-ui/models/role';
|
||||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||||
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
||||||
|
import nonEmptySet from 'consul-ui/utils/non-empty-set';
|
||||||
|
|
||||||
|
const Namespace = nonEmptySet('Namespace');
|
||||||
// TODO: Update to use this.formatDatacenter()
|
// TODO: Update to use this.formatDatacenter()
|
||||||
export default Adapter.extend({
|
export default Adapter.extend({
|
||||||
requestForQuery: function(request, { dc, ns, index, id }) {
|
requestForQuery: function(request, { dc, ns, index, id }) {
|
||||||
|
@ -32,7 +34,6 @@ export default Adapter.extend({
|
||||||
requestForCreateRecord: function(request, serialized, data) {
|
requestForCreateRecord: function(request, serialized, data) {
|
||||||
const params = {
|
const params = {
|
||||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||||
...this.formatNspace(data[NSPACE_KEY]),
|
|
||||||
};
|
};
|
||||||
return request`
|
return request`
|
||||||
PUT /v1/acl/role?${params}
|
PUT /v1/acl/role?${params}
|
||||||
|
@ -40,16 +41,15 @@ export default Adapter.extend({
|
||||||
${{
|
${{
|
||||||
Name: serialized.Name,
|
Name: serialized.Name,
|
||||||
Description: serialized.Description,
|
Description: serialized.Description,
|
||||||
Namespace: serialized.Namespace,
|
|
||||||
Policies: serialized.Policies,
|
Policies: serialized.Policies,
|
||||||
ServiceIdentities: serialized.ServiceIdentities,
|
ServiceIdentities: serialized.ServiceIdentities,
|
||||||
|
...Namespace(serialized.Namespace),
|
||||||
}}
|
}}
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
requestForUpdateRecord: function(request, serialized, data) {
|
requestForUpdateRecord: function(request, serialized, data) {
|
||||||
const params = {
|
const params = {
|
||||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||||
...this.formatNspace(data[NSPACE_KEY]),
|
|
||||||
};
|
};
|
||||||
return request`
|
return request`
|
||||||
PUT /v1/acl/role/${data[SLUG_KEY]}?${params}
|
PUT /v1/acl/role/${data[SLUG_KEY]}?${params}
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { inject as service } from '@ember/service';
|
||||||
import { SLUG_KEY } from 'consul-ui/models/token';
|
import { SLUG_KEY } from 'consul-ui/models/token';
|
||||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||||
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
||||||
|
import nonEmptySet from 'consul-ui/utils/non-empty-set';
|
||||||
|
|
||||||
|
const Namespace = nonEmptySet('Namespace');
|
||||||
// TODO: Update to use this.formatDatacenter()
|
// TODO: Update to use this.formatDatacenter()
|
||||||
export default Adapter.extend({
|
export default Adapter.extend({
|
||||||
store: service('store'),
|
store: service('store'),
|
||||||
|
@ -35,7 +37,6 @@ export default Adapter.extend({
|
||||||
requestForCreateRecord: function(request, serialized, data) {
|
requestForCreateRecord: function(request, serialized, data) {
|
||||||
const params = {
|
const params = {
|
||||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||||
...this.formatNspace(data[NSPACE_KEY]),
|
|
||||||
};
|
};
|
||||||
return request`
|
return request`
|
||||||
PUT /v1/acl/token?${params}
|
PUT /v1/acl/token?${params}
|
||||||
|
@ -46,6 +47,7 @@ export default Adapter.extend({
|
||||||
Roles: serialized.Roles,
|
Roles: serialized.Roles,
|
||||||
ServiceIdentities: serialized.ServiceIdentities,
|
ServiceIdentities: serialized.ServiceIdentities,
|
||||||
Local: serialized.Local,
|
Local: serialized.Local,
|
||||||
|
...Namespace(serialized.Namespace),
|
||||||
}}
|
}}
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
|
@ -66,13 +68,13 @@ export default Adapter.extend({
|
||||||
}
|
}
|
||||||
const params = {
|
const params = {
|
||||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||||
...this.formatNspace(data[NSPACE_KEY]),
|
|
||||||
};
|
};
|
||||||
return request`
|
return request`
|
||||||
PUT /v1/acl/token/${data[SLUG_KEY]}?${params}
|
PUT /v1/acl/token/${data[SLUG_KEY]}?${params}
|
||||||
|
|
||||||
${{
|
${{
|
||||||
Description: serialized.Description,
|
Description: serialized.Description,
|
||||||
|
Namespace: serialized.Namespace,
|
||||||
Policies: serialized.Policies,
|
Policies: serialized.Policies,
|
||||||
Roles: serialized.Roles,
|
Roles: serialized.Roles,
|
||||||
ServiceIdentities: serialized.ServiceIdentities,
|
ServiceIdentities: serialized.ServiceIdentities,
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default Component.extend(SlotsMixin, WithListeners, {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.searchable = this.container.searchable(this.type);
|
this.searchable = this.container.searchable(this.type);
|
||||||
this.form = this.formContainer.form(this.type);
|
this.form = this.formContainer.form(this.type);
|
||||||
this.form.clear({ Datacenter: this.dc });
|
this.form.clear({ Datacenter: this.dc, Namespace: this.nspace });
|
||||||
},
|
},
|
||||||
options: computed('selectedOptions.[]', 'allOptions.[]', function() {
|
options: computed('selectedOptions.[]', 'allOptions.[]', function() {
|
||||||
// It's not massively important here that we are defaulting `items` and
|
// It's not massively important here that we are defaulting `items` and
|
||||||
|
@ -52,7 +52,7 @@ export default Component.extend(SlotsMixin, WithListeners, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.form.clear({ Datacenter: this.dc });
|
this.form.clear({ Datacenter: this.dc, Namespace: this.nspace });
|
||||||
},
|
},
|
||||||
open: function() {
|
open: function() {
|
||||||
if (!get(this, 'allOptions.closed')) {
|
if (!get(this, 'allOptions.closed')) {
|
||||||
|
|
|
@ -8,12 +8,14 @@ export default Mixin.create(WithBlockingActions, {
|
||||||
actions: {
|
actions: {
|
||||||
use: function(item) {
|
use: function(item) {
|
||||||
return this.feedback.execute(() => {
|
return this.feedback.execute(() => {
|
||||||
// old style legacy ACLs don't have AccessorIDs
|
// old style legacy ACLs don't have AccessorIDs or Namespaces
|
||||||
// therefore set it to null, this way the frontend knows
|
// therefore set AccessorID to null, this way the frontend knows
|
||||||
// to use legacy ACLs
|
// to use legacy ACLs
|
||||||
|
// set the Namespace to just use default
|
||||||
return this.settings
|
return this.settings
|
||||||
.persist({
|
.persist({
|
||||||
token: {
|
token: {
|
||||||
|
Namespace: 'default',
|
||||||
AccessorID: null,
|
AccessorID: null,
|
||||||
SecretID: get(item, 'ID'),
|
SecretID: get(item, 'ID'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,9 +16,9 @@ export default Route.extend(WithBlockingActions, {
|
||||||
return this.settings
|
return this.settings
|
||||||
.persist({
|
.persist({
|
||||||
token: {
|
token: {
|
||||||
|
Namespace: get(item, 'Namespace'),
|
||||||
AccessorID: get(item, 'AccessorID'),
|
AccessorID: get(item, 'AccessorID'),
|
||||||
SecretID: secret,
|
SecretID: secret,
|
||||||
Namespace: get(item, 'Namespace'),
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(item => {
|
.then(item => {
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default Route.extend(WithIntentionActions, {
|
||||||
},
|
},
|
||||||
model: function(params) {
|
model: function(params) {
|
||||||
const dc = this.modelFor('dc').dc.Name;
|
const dc = this.modelFor('dc').dc.Name;
|
||||||
const nspace = this.modelFor('nspace').nspace.substr(1);
|
const nspace = '*';
|
||||||
this.item = this.repo.create({
|
this.item = this.repo.create({
|
||||||
Datacenter: dc,
|
Datacenter: dc,
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,6 +21,6 @@
|
||||||
{{#yield-slot name='policy' params=(block-params item)}}
|
{{#yield-slot name='policy' params=(block-params item)}}
|
||||||
{{yield}}
|
{{yield}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{policy-selector dc=dc items=item.Policies}}
|
{{policy-selector dc=dc nspace=nspace items=item.Policies}}
|
||||||
{{/yield-slot}}
|
{{/yield-slot}}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
{{#block-slot name='body'}}
|
{{#block-slot name='body'}}
|
||||||
|
|
||||||
<input id="{{name}}_state_role" type="radio" name="{{name}}[state]" value="role" checked={{if (eq state 'role') 'checked'}} onchange={{action 'change'}} />
|
<input id="{{name}}_state_role" type="radio" name="{{name}}[state]" value="role" checked={{if (eq state 'role') 'checked'}} onchange={{action 'change'}} />
|
||||||
{{#role-form form=form dc=dc}}
|
{{#role-form form=form dc=dc nspace=nspace}}
|
||||||
{{#block-slot name='policy'}}
|
{{#block-slot name='policy'}}
|
||||||
|
|
||||||
{{#policy-selector source=source dc=dc items=item.Policies}}
|
{{#policy-selector source=source dc=dc nspace=nspace items=item.Policies}}
|
||||||
{{#block-slot name='trigger'}}
|
{{#block-slot name='trigger'}}
|
||||||
<label for="{{name}}_state_policy" data-test-create-policy class="type-dialog">
|
<label for="{{name}}_state_policy" data-test-create-policy class="type-dialog">
|
||||||
<span>Create new policy</span>
|
<span>Create new policy</span>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<form>
|
<form>
|
||||||
{{role-form form=form item=item dc=dc}}
|
{{role-form form=form item=item dc=dc nspace=nspace}}
|
||||||
{{#if (and (not create) (gt items.length 0))}}
|
{{#if (and (not create) (gt items.length 0))}}
|
||||||
<h2>Where is this role used?</h2>
|
<h2>Where is this role used?</h2>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -23,14 +23,14 @@
|
||||||
<p>
|
<p>
|
||||||
By adding roles to this namespaces, you will apply them to all tokens created within this namespace.
|
By adding roles to this namespaces, you will apply them to all tokens created within this namespace.
|
||||||
</p>
|
</p>
|
||||||
{{role-selector dc=dc items=item.ACLs.RoleDefaults}}
|
{{role-selector dc=dc nspace='default' items=item.ACLs.RoleDefaults}}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset id="policies">
|
<fieldset id="policies">
|
||||||
<h2>Policies</h2>
|
<h2>Policies</h2>
|
||||||
<p>
|
<p>
|
||||||
By adding policies to this namespaces, you will apply them to all tokens created within this namespace.
|
By adding policies to this namespaces, you will apply them to all tokens created within this namespace.
|
||||||
</p>
|
</p>
|
||||||
{{policy-selector dc=dc items=item.ACLs.PolicyDefaults}}
|
{{policy-selector dc=dc nspace='default' items=item.ACLs.PolicyDefaults}}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
<li role="none">
|
<li role="none">
|
||||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.nspaces.edit' item.Name}}>Edit</a>
|
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.nspaces.edit' item.Name}}>Edit</a>
|
||||||
</li>
|
</li>
|
||||||
|
{{#if (not-eq item.Name 'default') }}
|
||||||
<li role="none" class="dangerous">
|
<li role="none" class="dangerous">
|
||||||
<label for={{confirm}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
<label for={{confirm}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
||||||
<div role="menu">
|
<div role="menu">
|
||||||
|
@ -83,6 +84,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
{{/if}}
|
||||||
{{/block-slot}}
|
{{/block-slot}}
|
||||||
{{/popover-menu}}
|
{{/popover-menu}}
|
||||||
{{/block-slot}}
|
{{/block-slot}}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default function(prop) {
|
||||||
|
return function(value) {
|
||||||
|
if (typeof value === 'undefined' || value === null || value === '') {
|
||||||
|
return {};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
[prop]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -82,6 +82,7 @@ module.exports = function(environment) {
|
||||||
case environment === 'test':
|
case environment === 'test':
|
||||||
ENV = Object.assign({}, ENV, {
|
ENV = Object.assign({}, ENV, {
|
||||||
locationType: 'none',
|
locationType: 'none',
|
||||||
|
CONSUL_NSPACES_TEST: true,
|
||||||
CONSUL_ACLS_ENABLED: true,
|
CONSUL_ACLS_ENABLED: true,
|
||||||
'@hashicorp/ember-cli-api-double': {
|
'@hashicorp/ember-cli-api-double': {
|
||||||
'auto-import': false,
|
'auto-import': false,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
|
@notNamespaceable
|
||||||
Feature: components / acl filter: Acl Filter
|
Feature: components / acl filter: Acl Filter
|
||||||
In order to find the acl token I'm looking for easier
|
In order to find the acl token I'm looking for easier
|
||||||
As a user
|
As a user
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: components / intention filter: Intention Filter
|
Feature: components / intention-filter: Intention Filter
|
||||||
In order to find the intention I'm looking for easier
|
In order to find the intention I'm looking for easier
|
||||||
As a user
|
As a user
|
||||||
I should be able to filter by 'policy' (allow/deny) and freetext search tokens by source and destination
|
I should be able to filter by 'policy' (allow/deny) and freetext search tokens by source and destination
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: acl forwarding
|
@notNamespaceable
|
||||||
|
Feature: dc / acls / index: acl forwarding
|
||||||
In order to arrive at a useful page when only specifying 'acls' in the url
|
In order to arrive at a useful page when only specifying 'acls' in the url
|
||||||
As a user
|
As a user
|
||||||
I should be redirected to the tokens page
|
I should be redirected to the tokens page
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
|
@notNamespaceable
|
||||||
Feature: dc / acls / list-order
|
Feature: dc / acls / list-order
|
||||||
In order to be able to find ACL tokens easier
|
In order to be able to find ACL tokens easier
|
||||||
As a user
|
As a user
|
||||||
|
|
|
@ -27,8 +27,9 @@ Feature: dc / acls / policies / as many / add existing: Add existing policy
|
||||||
And I click ".ember-power-select-option:nth-child(1)"
|
And I click ".ember-power-select-option:nth-child(1)"
|
||||||
And I see 2 policy models on the policies component
|
And I see 2 policy models on the policies component
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/[Model]/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" with the body from yaml
|
||||||
---
|
---
|
||||||
|
Namespace: @namespace
|
||||||
Policies:
|
Policies:
|
||||||
- ID: policy-1
|
- ID: policy-1
|
||||||
Name: Policy 1
|
Name: Policy 1
|
||||||
|
|
|
@ -22,18 +22,22 @@ Feature: dc / acls / policies / as many / add new: Add new policy
|
||||||
Rules: key {}
|
Rules: key {}
|
||||||
---
|
---
|
||||||
And I click submit on the policies.form
|
And I click submit on the policies.form
|
||||||
Then the last PUT request was made to "/v1/acl/policy?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/policy?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: New-Policy
|
Name: New-Policy
|
||||||
Description: New Policy Description
|
Description: New Policy Description
|
||||||
|
Namespace: @namespace
|
||||||
Rules: key {}
|
Rules: key {}
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/[Model]/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
Policies:
|
Policies:
|
||||||
- Name: New-Policy
|
- ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||||
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
Name: New-Policy
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/acls/[Model]s
|
Then the url should be /datacenter/acls/[Model]s
|
||||||
And "[data-notification]" has the "notification-update" class
|
And "[data-notification]" has the "notification-update" class
|
||||||
|
@ -53,8 +57,10 @@ Feature: dc / acls / policies / as many / add new: Add new policy
|
||||||
And I click serviceIdentity on the policies.form
|
And I click serviceIdentity on the policies.form
|
||||||
And I click submit on the policies.form
|
And I click submit on the policies.form
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/[Model]/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
ServiceIdentities:
|
ServiceIdentities:
|
||||||
- ServiceName: New-Service-Identity
|
- ServiceName: New-Service-Identity
|
||||||
---
|
---
|
||||||
|
@ -81,10 +87,11 @@ Feature: dc / acls / policies / as many / add new: Add new policy
|
||||||
Rules: key {}
|
Rules: key {}
|
||||||
---
|
---
|
||||||
And I click submit on the policies.form
|
And I click submit on the policies.form
|
||||||
Then the last PUT request was made to "/v1/acl/policy?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/policy?dc=datacenter" with the body from yaml
|
||||||
---
|
---
|
||||||
Name: New-Policy
|
Name: New-Policy
|
||||||
Description: New Policy Description
|
Description: New Policy Description
|
||||||
|
Namespace: @namespace
|
||||||
Rules: key {}
|
Rules: key {}
|
||||||
---
|
---
|
||||||
And I see error on the policies.form.rules like 'Invalid service policy: acl.ServicePolicy{Name:"service", Policy:"", Sentinel:acl.Sentinel{Code:"", EnforcementLevel:""}, Intentions:""}'
|
And I see error on the policies.form.rules like 'Invalid service policy: acl.ServicePolicy{Name:"service", Policy:"", Sentinel:acl.Sentinel{Code:"", EnforcementLevel:""}, Intentions:""}'
|
||||||
|
|
|
@ -17,13 +17,15 @@ Feature: dc / acls / policies / as many / remove: Remove
|
||||||
Then the url should be /datacenter/acls/[Model]s/key
|
Then the url should be /datacenter/acls/[Model]s/key
|
||||||
And I see 1 policy model on the policies component
|
And I see 1 policy model on the policies component
|
||||||
And I click expand on the policies.selectedOptions
|
And I click expand on the policies.selectedOptions
|
||||||
And the last GET request was made to "/v1/acl/policy/00000000-0000-0000-0000-000000000001?dc=datacenter"
|
And a GET request was made to "/v1/acl/policy/00000000-0000-0000-0000-000000000001?dc=datacenter&ns=@namespace"
|
||||||
And I click delete on the policies.selectedOptions
|
And I click delete on the policies.selectedOptions
|
||||||
And I click confirmDelete on the policies.selectedOptions
|
And I click confirmDelete on the policies.selectedOptions
|
||||||
And I see 0 policy models on the policies component
|
And I see 0 policy models on the policies component
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/[Model]/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
Policies: [[]]
|
Policies: [[]]
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/acls/[Model]s
|
Then the url should be /datacenter/acls/[Model]s
|
||||||
|
|
|
@ -14,10 +14,10 @@ Feature: dc / acls / policies / delete: Policy Delete
|
||||||
And I click actions on the policies
|
And I click actions on the policies
|
||||||
And I click delete on the policies
|
And I click delete on the policies
|
||||||
And I click confirmDelete on the policies
|
And I click confirmDelete on the policies
|
||||||
Then a DELETE request is made to "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=default"
|
Then a DELETE request was made to "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=@!namespace"
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Given the url "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=default" responds with a 500 status
|
Given the url "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=@namespace" responds with a 500 status
|
||||||
And I click actions on the policies
|
And I click actions on the policies
|
||||||
And I click delete on the policies
|
And I click delete on the policies
|
||||||
And I click confirmDelete on the policies
|
And I click confirmDelete on the policies
|
||||||
|
@ -31,7 +31,7 @@ Feature: dc / acls / policies / delete: Policy Delete
|
||||||
---
|
---
|
||||||
And I click delete
|
And I click delete
|
||||||
And I click confirmDelete on the deleteModal
|
And I click confirmDelete on the deleteModal
|
||||||
Then a DELETE request is made to "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=default"
|
Then a DELETE request was made to "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=@!namespace"
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
When I visit the policy page for yaml
|
When I visit the policy page for yaml
|
||||||
|
@ -39,7 +39,7 @@ Feature: dc / acls / policies / delete: Policy Delete
|
||||||
dc: datacenter
|
dc: datacenter
|
||||||
policy: 1981f51d-301a-497b-89a0-05112ef02b4b
|
policy: 1981f51d-301a-497b-89a0-05112ef02b4b
|
||||||
---
|
---
|
||||||
Given the url "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=default" responds with a 500 status
|
Given the url "/v1/acl/policy/1981f51d-301a-497b-89a0-05112ef02b4b?dc=datacenter&ns=@namespace" responds with a 500 status
|
||||||
And I click delete
|
And I click delete
|
||||||
And I click confirmDelete on the deleteModal
|
And I click confirmDelete on the deleteModal
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
|
|
|
@ -25,13 +25,16 @@ Feature: dc / acls / policies / update: ACL Policy Update
|
||||||
And I click validDatacenters
|
And I click validDatacenters
|
||||||
And I click datacenter
|
And I click datacenter
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/policy/policy-id?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/policy/policy-id?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: [Name]
|
Name: [Name]
|
||||||
Description: [Description]
|
Description: [Description]
|
||||||
Rules: [Rules]
|
Rules: [Rules]
|
||||||
|
Namespace: @namespace
|
||||||
Datacenters:
|
Datacenters:
|
||||||
- datacenter
|
- datacenter
|
||||||
|
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/acls/policies
|
Then the url should be /datacenter/acls/policies
|
||||||
And "[data-notification]" has the "notification-update" class
|
And "[data-notification]" has the "notification-update" class
|
||||||
|
|
|
@ -32,8 +32,10 @@ Feature: dc / acls / roles / as many / add existing: Add existing
|
||||||
Description: The Description
|
Description: The Description
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
Description: The Description
|
Description: The Description
|
||||||
Roles:
|
Roles:
|
||||||
- ID: role-1
|
- ID: role-1
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / roles / as many / add new: Add new
|
@notNamespaceable
|
||||||
|
Feature: dc / acls / roles / as-many / add-new: Add new
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
And 1 token model from yaml
|
And 1 token model from yaml
|
||||||
|
@ -29,15 +30,19 @@ Feature: dc / acls / roles / as many / add new: Add new
|
||||||
---
|
---
|
||||||
Scenario: Add Policy-less Role
|
Scenario: Add Policy-less Role
|
||||||
And I click submit on the roles.form
|
And I click submit on the roles.form
|
||||||
Then the last PUT request was made to "/v1/acl/role?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: New-Role
|
Name: New-Role
|
||||||
|
Namespace: @namespace
|
||||||
Description: New Role Description
|
Description: New Role Description
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Description: The Description
|
Description: The Description
|
||||||
|
Namespace: @namespace
|
||||||
Roles:
|
Roles:
|
||||||
- Name: New-Role
|
- Name: New-Role
|
||||||
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||||
|
@ -49,18 +54,22 @@ Feature: dc / acls / roles / as many / add new: Add new
|
||||||
And I click "#new-role-toggle + div .ember-power-select-trigger"
|
And I click "#new-role-toggle + div .ember-power-select-trigger"
|
||||||
And I click ".ember-power-select-option:first-child"
|
And I click ".ember-power-select-option:first-child"
|
||||||
And I click submit on the roles.form
|
And I click submit on the roles.form
|
||||||
Then the last PUT request was made to "/v1/acl/role?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: New-Role
|
Name: New-Role
|
||||||
Description: New Role Description
|
Description: New Role Description
|
||||||
|
Namespace: @namespace
|
||||||
Policies:
|
Policies:
|
||||||
- ID: policy-1
|
- ID: policy-1
|
||||||
Name: policy
|
Name: policy
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Description: The Description
|
Description: The Description
|
||||||
|
Namespace: @namespace
|
||||||
Roles:
|
Roles:
|
||||||
- Name: New-Role
|
- Name: New-Role
|
||||||
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||||
|
@ -78,26 +87,32 @@ Feature: dc / acls / roles / as many / add new: Add new
|
||||||
---
|
---
|
||||||
# This next line is actually the popped up policyForm due to the way things currently work
|
# This next line is actually the popped up policyForm due to the way things currently work
|
||||||
And I click submit on the roles.form
|
And I click submit on the roles.form
|
||||||
Then the last PUT request was made to "/v1/acl/policy?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/policy?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: New-Policy
|
Name: New-Policy
|
||||||
Description: New Policy Description
|
Description: New Policy Description
|
||||||
|
Namespace: @namespace
|
||||||
Rules: key {}
|
Rules: key {}
|
||||||
---
|
---
|
||||||
And I click submit on the roles.form
|
And I click submit on the roles.form
|
||||||
Then the last PUT request was made to "/v1/acl/role?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: New-Role
|
Name: New-Role
|
||||||
Description: New Role Description
|
Description: New Role Description
|
||||||
|
Namespace: @namespace
|
||||||
Policies:
|
Policies:
|
||||||
# TODO: Ouch, we need to do deep partial comparisons here
|
# TODO: Ouch, we need to do deep partial comparisons here
|
||||||
- ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
- ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||||
Name: New-Policy
|
Name: New-Policy
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Description: The Description
|
Description: The Description
|
||||||
|
Namespace: @namespace
|
||||||
Roles:
|
Roles:
|
||||||
- Name: New-Role
|
- Name: New-Role
|
||||||
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||||
|
@ -115,17 +130,21 @@ Feature: dc / acls / roles / as many / add new: Add new
|
||||||
# This next line is actually the popped up policyForm due to the way things currently work
|
# This next line is actually the popped up policyForm due to the way things currently work
|
||||||
And I click submit on the roles.form
|
And I click submit on the roles.form
|
||||||
And I click submit on the roles.form
|
And I click submit on the roles.form
|
||||||
Then the last PUT request was made to "/v1/acl/role?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: New-Role
|
Name: New-Role
|
||||||
Description: New Role Description
|
Description: New Role Description
|
||||||
|
Namespace: @namespace
|
||||||
ServiceIdentities:
|
ServiceIdentities:
|
||||||
- ServiceName: New-Service-Identity
|
- ServiceName: New-Service-Identity
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Description: The Description
|
Description: The Description
|
||||||
|
Namespace: @namespace
|
||||||
Roles:
|
Roles:
|
||||||
- Name: New-Role
|
- Name: New-Role
|
||||||
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / roles / as many / list: List
|
Feature: dc / acls / roles / as-many / list: List
|
||||||
Scenario:
|
Scenario:
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
And 1 token model from yaml
|
And 1 token model from yaml
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / roles / as many / remove: Remove
|
Feature: dc / acls / roles / as-many / remove: Remove
|
||||||
Scenario:
|
Scenario:
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
And 1 token model from yaml
|
And 1 token model from yaml
|
||||||
|
@ -21,8 +21,10 @@ Feature: dc / acls / roles / as many / remove: Remove
|
||||||
And I click confirmDelete on the roles.selectedOptions
|
And I click confirmDelete on the roles.selectedOptions
|
||||||
And I see 0 role models on the roles component
|
And I see 0 role models on the roles component
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
Roles: []
|
Roles: []
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/acls/tokens
|
Then the url should be /datacenter/acls/tokens
|
||||||
|
|
|
@ -21,8 +21,10 @@ Feature: dc / acls / roles / update: ACL Role Update
|
||||||
Description: [Description]
|
Description: [Description]
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/role/role-id?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/role/role-id?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
Name: [Name]
|
Name: [Name]
|
||||||
Description: [Description]
|
Description: [Description]
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / tokens / anonymous no delete: The anonymous token has no delete buttons
|
Feature: dc / acls / tokens / anonymous-no-delete: The anonymous token has no delete buttons
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And 1 token model from yaml
|
And 1 token model from yaml
|
||||||
|
|
|
@ -14,7 +14,7 @@ Feature: dc / acls / tokens / clone: Cloning an ACL token
|
||||||
---
|
---
|
||||||
And I click actions on the tokens
|
And I click actions on the tokens
|
||||||
And I click clone on the tokens
|
And I click clone on the tokens
|
||||||
Then a PUT request is made to "/v1/acl/token/token/clone?dc=datacenter&ns=default"
|
Then a PUT request was made to "/v1/acl/token/token/clone?dc=datacenter&ns=@!namespace"
|
||||||
Then "[data-notification]" has the "notification-clone" class
|
Then "[data-notification]" has the "notification-clone" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Scenario: Using an ACL token from the detail page
|
Scenario: Using an ACL token from the detail page
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
|
@notNamespaceable
|
||||||
Feature: dc / acls / tokens / legacy / update: ACL Token Update
|
Feature: dc / acls / tokens / legacy / update: ACL Token Update
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
|
@ -24,9 +25,10 @@ Feature: dc / acls / tokens / legacy / update: ACL Token Update
|
||||||
# TODO: Remove this when I'm 100% sure token types are gone
|
# TODO: Remove this when I'm 100% sure token types are gone
|
||||||
# And I click "[value=[Type]]"
|
# And I click "[value=[Type]]"
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/update?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/update?dc=datacenter" from yaml
|
||||||
# You can no longer edit Type but make sure it gets sent
|
# You can no longer edit Type but make sure it gets sent
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
ID: secret
|
ID: secret
|
||||||
Name: [Name]
|
Name: [Name]
|
||||||
Type: client
|
Type: client
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / tokens / index: ACL Login Errors
|
Feature: dc / acls / tokens / login-errors: ACL Login Errors
|
||||||
|
|
||||||
Scenario: I get any 500 error that is not the specific legacy token cluster one
|
Scenario: I get any 500 error that is not the specific legacy token cluster one
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
Given the url "/v1/acl/tokens" responds with a 500 status
|
Given the url "/v1/acl/tokens?ns=@namespace" responds with a 500 status
|
||||||
When I visit the tokens page for yaml
|
When I visit the tokens page for yaml
|
||||||
---
|
---
|
||||||
dc: dc-1
|
dc: dc-1
|
||||||
|
@ -12,7 +12,7 @@ Feature: dc / acls / tokens / index: ACL Login Errors
|
||||||
Then I see the text "500 (The backend responded with an error)" in "[data-test-error]"
|
Then I see the text "500 (The backend responded with an error)" in "[data-test-error]"
|
||||||
Scenario: I get a 500 error from acl/tokens that is the specific legacy one
|
Scenario: I get a 500 error from acl/tokens that is the specific legacy one
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And the url "/v1/acl/tokens" responds with from yaml
|
And the url "/v1/acl/tokens?ns=@namespace" responds with from yaml
|
||||||
---
|
---
|
||||||
status: 500
|
status: 500
|
||||||
body: "rpc error making call: rpc: can't find method ACL.TokenRead"
|
body: "rpc error making call: rpc: can't find method ACL.TokenRead"
|
||||||
|
@ -23,9 +23,10 @@ Feature: dc / acls / tokens / index: ACL Login Errors
|
||||||
---
|
---
|
||||||
Then the url should be /dc-1/acls/tokens
|
Then the url should be /dc-1/acls/tokens
|
||||||
Then ".app-view" has the "unauthorized" class
|
Then ".app-view" has the "unauthorized" class
|
||||||
|
@notNamespaceable
|
||||||
Scenario: I get a 500 error from acl/token/self that is the specific legacy one
|
Scenario: I get a 500 error from acl/token/self that is the specific legacy one
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
Given the url "/v1/acl/tokens" responds with from yaml
|
Given the url "/v1/acl/tokens?ns=@namespace" responds with from yaml
|
||||||
---
|
---
|
||||||
status: 500
|
status: 500
|
||||||
body: "rpc error making call: rpc: can't find method ACL.TokenRead"
|
body: "rpc error making call: rpc: can't find method ACL.TokenRead"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / acls / tokens / own no delete: The your current token has no delete buttons
|
Feature: dc / acls / tokens / own-no-delete: The your current token has no delete buttons
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And 1 token model from yaml
|
And 1 token model from yaml
|
||||||
|
@ -24,7 +24,7 @@ Feature: dc / acls / tokens / own no delete: The your current token has no delet
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\",\"Namespace\":\"default\"}"
|
consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\",\"Namespace\":\"@namespace\"}"
|
||||||
---
|
---
|
||||||
And I click actions on the tokens
|
And I click actions on the tokens
|
||||||
Then I don't see delete on the tokens
|
Then I don't see delete on the tokens
|
||||||
|
|
|
@ -19,8 +19,10 @@ Feature: dc / acls / tokens / update: ACL Token Update
|
||||||
Description: [Description]
|
Description: [Description]
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/token/key?dc=datacenter&ns=default" with the body from yaml
|
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
|
Namespace: @namespace
|
||||||
Description: [Description]
|
Description: [Description]
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/acls/tokens
|
Then the url should be /datacenter/acls/tokens
|
||||||
|
|
|
@ -23,7 +23,7 @@ Feature: dc / acls / tokens / use: Using an ACL token
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\",\"Namespace\":\"default\"}"
|
consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\",\"Namespace\":\"@namespace\"}"
|
||||||
---
|
---
|
||||||
Scenario: Using an ACL token from the detail page
|
Scenario: Using an ACL token from the detail page
|
||||||
When I visit the token page for yaml
|
When I visit the token page for yaml
|
||||||
|
@ -41,5 +41,5 @@ Feature: dc / acls / tokens / use: Using an ACL token
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\",\"Namespace\":\"default\"}"
|
consul:token: "{\"AccessorID\":\"token\",\"SecretID\":\"ee52203d-989f-4f7a-ab5a-2bef004164ca\",\"Namespace\":\"@namespace\"}"
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
|
@notNamespaceable
|
||||||
Feature: dc / acls / update: ACL Update
|
Feature: dc / acls / update: ACL Update
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
|
@ -20,8 +21,9 @@ Feature: dc / acls / update: ACL Update
|
||||||
---
|
---
|
||||||
And I click "[value=[Type]]"
|
And I click "[value=[Type]]"
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/acl/update?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/acl/update?dc=datacenter" from yaml
|
||||||
---
|
---
|
||||||
|
body:
|
||||||
Name: [Name]
|
Name: [Name]
|
||||||
Type: [Type]
|
Type: [Type]
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
|
@notNamespaceable
|
||||||
Feature: dc / acls / use: Using an ACL token
|
Feature: dc / acls / use: Using an ACL token
|
||||||
Background:
|
Background:
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
|
@ -14,7 +15,7 @@ Feature: dc / acls / use: Using an ACL token
|
||||||
---
|
---
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: '{"AccessorID":null,"SecretID":"id"}'
|
consul:token: '{"Namespace":"@namespace","AccessorID":null,"SecretID":"id"}'
|
||||||
---
|
---
|
||||||
And I click actions on the acls
|
And I click actions on the acls
|
||||||
And I click use on the acls
|
And I click use on the acls
|
||||||
|
@ -23,7 +24,7 @@ Feature: dc / acls / use: Using an ACL token
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: '{"AccessorID":null,"SecretID":"token"}'
|
consul:token: '{"Namespace":"@namespace","AccessorID":null,"SecretID":"token"}'
|
||||||
---
|
---
|
||||||
Scenario: Using an ACL token from the detail page
|
Scenario: Using an ACL token from the detail page
|
||||||
When I visit the acl page for yaml
|
When I visit the acl page for yaml
|
||||||
|
@ -33,7 +34,7 @@ Feature: dc / acls / use: Using an ACL token
|
||||||
---
|
---
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: '{"AccessorID":null,"SecretID":"id"}'
|
consul:token: '{"Namespace":"@namespace","AccessorID":null,"SecretID":"id"}'
|
||||||
---
|
---
|
||||||
And I click use
|
And I click use
|
||||||
And I click confirmUse
|
And I click confirmUse
|
||||||
|
@ -41,5 +42,5 @@ Feature: dc / acls / use: Using an ACL token
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Then I have settings like yaml
|
Then I have settings like yaml
|
||||||
---
|
---
|
||||||
consul:token: '{"AccessorID":null,"SecretID":"token"}'
|
consul:token: '{"Namespace":"@namespace","AccessorID":null,"SecretID":"token"}'
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc forwarding
|
Feature: dc / forwarding
|
||||||
In order to arrive at a useful page when only specifying a dc in the url
|
In order to arrive at a useful page when only specifying a dc in the url
|
||||||
As a user
|
As a user
|
||||||
I should be redirected to the services page for the dc
|
I should be redirected to the services page for the dc
|
||||||
|
@notNamespaceable
|
||||||
Scenario: Arriving at the datacenter index page with no other url info
|
Scenario: Arriving at the datacenter index page with no other url info
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
When I visit the dcs page for yaml
|
When I visit the dcs page for yaml
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: Datacenters
|
Feature: dc / index: Datacenters
|
||||||
@ignore
|
@ignore
|
||||||
Scenario: Arriving at the service page
|
Scenario: Arriving at the service page
|
||||||
Given 10 datacenter models
|
Given 10 datacenter models
|
||||||
|
|
|
@ -32,7 +32,7 @@ Feature: dc / intentions / create: Intention Create
|
||||||
# Specifically set deny
|
# Specifically set deny
|
||||||
And I click "[value=deny]"
|
And I click "[value=deny]"
|
||||||
And I submit
|
And I submit
|
||||||
Then a POST request is made to "/v1/connect/intentions?dc=datacenter" with the body from yaml
|
Then a POST request was made to "/v1/connect/intentions?dc=datacenter" with the body from yaml
|
||||||
---
|
---
|
||||||
SourceName: web
|
SourceName: web
|
||||||
DestinationName: db
|
DestinationName: db
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / intentions / filtered select: Intention Service Select Dropdowns
|
Feature: dc / intentions / filtered-select: Intention Service Select Dropdowns
|
||||||
In order to use services as intention sources and destinations
|
In order to use services as intention sources and destinations
|
||||||
As a user
|
As a user
|
||||||
I want to be able to choose see existing services in the dropdown, but not existing proxy services
|
I want to be able to choose see existing services in the dropdown, but not existing proxy services
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / intentions / form select: Intention Service Select Dropdowns
|
Feature: dc / intentions / form-select: Intention Service Select Dropdowns
|
||||||
In order to set future Consul services as intention sources and destinations
|
In order to set future Consul services as intention sources and destinations
|
||||||
As a user
|
As a user
|
||||||
I want to type into the autocomplete and select what I've typed to use it as the future service
|
I want to type into the autocomplete and select what I've typed to use it as the future service
|
||||||
|
|
|
@ -19,7 +19,7 @@ Feature: dc / intentions / update: Intention Update
|
||||||
---
|
---
|
||||||
And I click "[value=[Action]]"
|
And I click "[value=[Action]]"
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/connect/intentions/intention-id?dc=datacenter" with the body from yaml
|
Then a PUT request was made to "/v1/connect/intentions/intention-id?dc=datacenter" with the body from yaml
|
||||||
---
|
---
|
||||||
Description: [Description]
|
Description: [Description]
|
||||||
Action: [Action]
|
Action: [Action]
|
||||||
|
|
|
@ -19,12 +19,12 @@ Feature: dc / kvs / sessions / invalidate: Invalidate Lock Sessions
|
||||||
Scenario: Invalidating the lock session
|
Scenario: Invalidating the lock session
|
||||||
And I click delete on the session
|
And I click delete on the session
|
||||||
And I click confirmDelete on the session
|
And I click confirmDelete on the session
|
||||||
Then the last PUT request was made to "/v1/session/destroy/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter&ns=default"
|
Then a PUT request was made to "/v1/session/destroy/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter&ns=@!namespace"
|
||||||
Then the url should be /datacenter/kv/key/edit
|
Then the url should be /datacenter/kv/key/edit
|
||||||
And "[data-notification]" has the "notification-deletesession" class
|
And "[data-notification]" has the "notification-deletesession" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Scenario: Invalidating a lock session and receiving an error
|
Scenario: Invalidating a lock session and receiving an error
|
||||||
Given the url "/v1/session/destroy/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter&ns=default" responds with a 500 status
|
Given the url "/v1/session/destroy/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter&ns=@!namespace" responds with a 500 status
|
||||||
And I click delete on the session
|
And I click delete on the session
|
||||||
And I click confirmDelete on the session
|
And I click confirmDelete on the session
|
||||||
Then the url should be /datacenter/kv/key/edit
|
Then the url should be /datacenter/kv/key/edit
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / kvs / trailing slash
|
Feature: dc / kvs / trailing-slash
|
||||||
Scenario: I have 10 folders
|
Scenario: I have 10 folders
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
And 10 kv models from yaml
|
And 10 kv models from yaml
|
||||||
|
@ -9,11 +9,11 @@ Feature: dc / kvs / trailing slash
|
||||||
kv: foo/bar
|
kv: foo/bar
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/kv/foo/bar/
|
Then the url should be /datacenter/kv/foo/bar/
|
||||||
And the last GET request was made to "/v1/kv/foo/bar/?keys&dc=datacenter&separator=%2F"
|
And a GET request was made to "/v1/kv/foo/bar/?keys&dc=datacenter&separator=%2F&ns=@namespace"
|
||||||
When I visit the kvs page for yaml
|
When I visit the kvs page for yaml
|
||||||
---
|
---
|
||||||
dc: datacenter
|
dc: datacenter
|
||||||
kv: foo/bar/
|
kv: foo/bar/
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/kv/foo/bar/
|
Then the url should be /datacenter/kv/foo/bar/
|
||||||
And the last GET request was made to "/v1/kv/foo/bar/?keys&dc=datacenter&separator=%2F"
|
And a GET request was made to "/v1/kv/foo/bar/?keys&dc=datacenter&separator=%2F&ns=@namespace"
|
||||||
|
|
|
@ -20,7 +20,7 @@ Feature: dc / kvs / update: KV Update
|
||||||
value: [Value]
|
value: [Value]
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/kv/[EncodedName]?dc=datacenter&ns=default" with the body "[Value]"
|
Then a PUT request was made to "/v1/kv/[EncodedName]?dc=datacenter&ns=@!namespace" with the body "[Value]"
|
||||||
And "[data-notification]" has the "notification-update" class
|
And "[data-notification]" has the "notification-update" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Where:
|
Where:
|
||||||
|
@ -50,7 +50,7 @@ Feature: dc / kvs / update: KV Update
|
||||||
value: ' '
|
value: ' '
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/kv/key?dc=datacenter&ns=default" with the body " "
|
Then a PUT request was made to "/v1/kv/key?dc=datacenter&ns=@!namespace" with the body " "
|
||||||
Then the url should be /datacenter/kv
|
Then the url should be /datacenter/kv
|
||||||
And "[data-notification]" has the "notification-update" class
|
And "[data-notification]" has the "notification-update" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
|
@ -72,7 +72,7 @@ Feature: dc / kvs / update: KV Update
|
||||||
value: ''
|
value: ''
|
||||||
---
|
---
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/kv/key?dc=datacenter&ns=default" with no body
|
Then a PUT request was made to "/v1/kv/key?dc=datacenter&ns=@!namespace" with no body
|
||||||
Then the url should be /datacenter/kv
|
Then the url should be /datacenter/kv
|
||||||
And "[data-notification]" has the "notification-update" class
|
And "[data-notification]" has the "notification-update" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
|
@ -89,7 +89,7 @@ Feature: dc / kvs / update: KV Update
|
||||||
---
|
---
|
||||||
Then the url should be /datacenter/kv/key/edit
|
Then the url should be /datacenter/kv/key/edit
|
||||||
And I submit
|
And I submit
|
||||||
Then a PUT request is made to "/v1/kv/key?dc=datacenter&ns=default" with no body
|
Then a PUT request was made to "/v1/kv/key?dc=datacenter&ns=@!namespace" with no body
|
||||||
Then the url should be /datacenter/kv
|
Then the url should be /datacenter/kv
|
||||||
And "[data-notification]" has the "notification-update" class
|
And "[data-notification]" has the "notification-update" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc > list: List Models
|
Feature: dc / list: List Models
|
||||||
Scenario: Listing [Model]
|
Scenario: Listing [Model]
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And 3 [Model] models
|
And 3 [Model] models
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: Hedge for if nodes come in over the API with no ID
|
Feature: dc / nodes / empty-ids: Hedge for if nodes come in over the API with no ID
|
||||||
Scenario: A node list with some missing IDs
|
Scenario: A node list with some missing IDs
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And 5 node models from yaml
|
And 5 node models from yaml
|
||||||
|
|
|
@ -25,12 +25,12 @@ Feature: dc / nodes / sessions / invalidate: Invalidate Lock Sessions
|
||||||
Scenario: Invalidating the lock session
|
Scenario: Invalidating the lock session
|
||||||
And I click delete on the sessions
|
And I click delete on the sessions
|
||||||
And I click confirmDelete on the sessions
|
And I click confirmDelete on the sessions
|
||||||
Then the last PUT request was made to "/v1/session/destroy/7bbbd8bb-fff3-4292-b6e3-cfedd788546a?dc=dc1&ns=default"
|
Then a PUT request was made to "/v1/session/destroy/7bbbd8bb-fff3-4292-b6e3-cfedd788546a?dc=dc1&ns=@!namespace"
|
||||||
Then the url should be /dc1/nodes/node-0
|
Then the url should be /dc1/nodes/node-0
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Scenario: Invalidating a lock session and receiving an error
|
Scenario: Invalidating a lock session and receiving an error
|
||||||
Given the url "/v1/session/destroy/7bbbd8bb-fff3-4292-b6e3-cfedd788546a?dc=dc1&ns=default" responds with a 500 status
|
Given the url "/v1/session/destroy/7bbbd8bb-fff3-4292-b6e3-cfedd788546a?dc=dc1&ns=@!namespace" responds with a 500 status
|
||||||
And I click delete on the sessions
|
And I click delete on the sessions
|
||||||
And I click confirmDelete on the sessions
|
And I click confirmDelete on the sessions
|
||||||
Then the url should be /dc1/nodes/node-0
|
Then the url should be /dc1/nodes/node-0
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
@setupApplicationTest
|
||||||
|
Feature: dc / nspaces / index: Nspaces List
|
||||||
|
Background:
|
||||||
|
Given settings from yaml
|
||||||
|
---
|
||||||
|
consul:token:
|
||||||
|
SecretID: secret
|
||||||
|
AccessorID: accessor
|
||||||
|
Namespace: default
|
||||||
|
---
|
||||||
|
And 1 datacenter model with the value "dc-1"
|
||||||
|
And 3 nspace models
|
||||||
|
When I visit the nspaces page for yaml
|
||||||
|
---
|
||||||
|
dc: dc-1
|
||||||
|
---
|
||||||
|
Then the url should be /dc-1/namespaces
|
||||||
|
Scenario:
|
||||||
|
Then I see 3 nspace models
|
||||||
|
Scenario: Searching the nspaces
|
||||||
|
Then I see 3 nspace models
|
||||||
|
Then I fill in with yaml
|
||||||
|
---
|
||||||
|
s: default
|
||||||
|
---
|
||||||
|
And I see 1 nspace model
|
||||||
|
And I see 1 nspace model with the description "The default namespace"
|
||||||
|
Scenario: The default namespace can't be deleted
|
||||||
|
Then I see 3 nspace models
|
||||||
|
And I click actions on the nspaces
|
||||||
|
Then I don't see delete on the nspaces
|
|
@ -0,0 +1,42 @@
|
||||||
|
@setupApplicationTest
|
||||||
|
Feature: dc / nspaces / update: Nspace Update
|
||||||
|
Background:
|
||||||
|
Given 1 datacenter model with the value "datacenter"
|
||||||
|
And 1 nspace model from yaml
|
||||||
|
---
|
||||||
|
Name: namespace
|
||||||
|
Description: empty
|
||||||
|
PolicyDefaults: ~
|
||||||
|
---
|
||||||
|
When I visit the nspace page for yaml
|
||||||
|
---
|
||||||
|
dc: datacenter
|
||||||
|
namespace: namespace
|
||||||
|
---
|
||||||
|
Then the url should be /datacenter/namespaces/namespace
|
||||||
|
Scenario: Update to [Description]
|
||||||
|
Then I fill in with yaml
|
||||||
|
---
|
||||||
|
Description: [Description]
|
||||||
|
---
|
||||||
|
And I submit
|
||||||
|
Then a PUT request was made to "/v1/namespace/namespace" from yaml
|
||||||
|
---
|
||||||
|
body:
|
||||||
|
Description: [Description]
|
||||||
|
---
|
||||||
|
Then the url should be /datacenter/namespaces
|
||||||
|
And "[data-notification]" has the "notification-update" class
|
||||||
|
And "[data-notification]" has the "success" class
|
||||||
|
Where:
|
||||||
|
---------------------------
|
||||||
|
| Description |
|
||||||
|
| description |
|
||||||
|
| description with spaces |
|
||||||
|
---------------------------
|
||||||
|
Scenario: There was an error saving the key
|
||||||
|
Given the url "/v1/namespace/namespace" responds with a 500 status
|
||||||
|
And I submit
|
||||||
|
Then the url should be /datacenter/namespaces/namespace
|
||||||
|
Then "[data-notification]" has the "notification-update" class
|
||||||
|
And "[data-notification]" has the "error" class
|
|
@ -11,6 +11,7 @@ Feature: dc / services / error
|
||||||
dc: 404-datacenter
|
dc: 404-datacenter
|
||||||
---
|
---
|
||||||
Then I see the text "404 (Page not found)" in "[data-test-error]"
|
Then I see the text "404 (Page not found)" in "[data-test-error]"
|
||||||
|
@notNamespaceable
|
||||||
Scenario: Arriving at the service page
|
Scenario: Arriving at the service page
|
||||||
Given 2 datacenter models from yaml
|
Given 2 datacenter models from yaml
|
||||||
---
|
---
|
||||||
|
@ -23,5 +24,8 @@ Feature: dc / services / error
|
||||||
dc: dc-1
|
dc: dc-1
|
||||||
---
|
---
|
||||||
Then I see the text "500 (The backend responded with an error)" in "[data-test-error]"
|
Then I see the text "500 (The backend responded with an error)" in "[data-test-error]"
|
||||||
|
# This is the actual step that works slightly differently
|
||||||
|
# When running through namespaces as the dc menu says 'Error'
|
||||||
|
# which is still kind of ok
|
||||||
When I click dc on the navigation
|
When I click dc on the navigation
|
||||||
And I see 2 datacenter models
|
And I see 2 datacenter models
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: dc / services: List Services
|
Feature: dc / services / index: List Services
|
||||||
Scenario:
|
Scenario:
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
And 6 service models from yaml
|
And 6 service models from yaml
|
||||||
|
|
|
@ -17,17 +17,18 @@ Feature: deleting: Deleting items with confirmations, success and error notifica
|
||||||
And I click actions on the [Listing]
|
And I click actions on the [Listing]
|
||||||
And I click delete on the [Listing]
|
And I click delete on the [Listing]
|
||||||
And I click confirmDelete on the [Listing]
|
And I click confirmDelete on the [Listing]
|
||||||
Then a [Method] request is made to "[URL]"
|
Then a [Method] request was made to "[URL]"
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
Where:
|
Where:
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
| Edit | Listing | Method | URL | Data | Slug |
|
| Edit | Listing | Method | URL | Data |
|
||||||
# | acl | acls | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | acl: something |
|
| kv | kvs | DELETE | /v1/kv/key-name?dc=datacenter&ns=@!namespace | ["key-name"] |
|
||||||
| kv | kvs | DELETE | /v1/kv/key-name?dc=datacenter&ns=default | ["key-name"] | kv: key-name |
|
| intention | intentions | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} |
|
||||||
| intention | intentions | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} | intention: 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"} |
|
||||||
| token | tokens | DELETE | /v1/acl/token/001fda31-194e-4ff1-a5ec-589abf2cafd0?dc=datacenter&ns=default | {"AccessorID": "001fda31-194e-4ff1-a5ec-589abf2cafd0"} | token: 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
|
Scenario: Deleting a [Model] from the [Model] detail page
|
||||||
When I visit the [Model] page for yaml
|
When I visit the [Model] page for yaml
|
||||||
---
|
---
|
||||||
|
@ -36,7 +37,7 @@ Feature: deleting: Deleting items with confirmations, success and error notifica
|
||||||
---
|
---
|
||||||
And I click delete
|
And I click delete
|
||||||
And I click confirmDelete
|
And I click confirmDelete
|
||||||
Then a [Method] request is made to "[URL]"
|
Then a [Method] request was made to "[URL]"
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "success" class
|
And "[data-notification]" has the "success" class
|
||||||
When I visit the [Model] page for yaml
|
When I visit the [Model] page for yaml
|
||||||
|
@ -50,13 +51,14 @@ Feature: deleting: Deleting items with confirmations, success and error notifica
|
||||||
And "[data-notification]" has the "notification-delete" class
|
And "[data-notification]" has the "notification-delete" class
|
||||||
And "[data-notification]" has the "error" class
|
And "[data-notification]" has the "error" class
|
||||||
Where:
|
Where:
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
| Model | Method | URL | Slug |
|
| Model | Method | URL | Slug |
|
||||||
# | acl | PUT | /v1/acl/destroy/something?dc=datacenter | acl: something |
|
| kv | DELETE | /v1/kv/key-name?dc=datacenter&ns=@!namespace | kv: key-name |
|
||||||
| kv | DELETE | /v1/kv/key-name?dc=datacenter&ns=default | kv: key-name |
|
|
||||||
| intention | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca |
|
| 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=default | token: 001fda31-194e-4ff1-a5ec-589abf2cafd0 |
|
| 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
|
@ignore
|
||||||
Scenario: Sort out the wide tables ^
|
Scenario: Sort out the wide tables ^
|
||||||
Then ok
|
Then ok
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: index forwarding
|
@notNamespaceable
|
||||||
|
Feature: index-forwarding
|
||||||
Scenario: Arriving at the index page when there is only one datacenter
|
Scenario: Arriving at the index page when there is only one datacenter
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
When I visit the index page
|
When I visit the index page
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: Page Navigation
|
Feature: page-navigation
|
||||||
In order to view all the data in consul
|
In order to view all the data in consul
|
||||||
As a user
|
As a user
|
||||||
I should be able to visit every page and view data in a HTML from the API
|
I should be able to visit every page and view data in a HTML from the API
|
||||||
|
@ -11,7 +11,7 @@ Feature: Page Navigation
|
||||||
dc: dc-1
|
dc: dc-1
|
||||||
---
|
---
|
||||||
Then the url should be /dc-1/services
|
Then the url should be /dc-1/services
|
||||||
Then the last GET request was made to "/v1/internal/ui/services?dc=dc-1"
|
Then a GET request was made to "/v1/internal/ui/services?dc=dc-1&ns=@namespace"
|
||||||
Scenario: Clicking [Link] in the navigation takes me to [URL]
|
Scenario: Clicking [Link] in the navigation takes me to [URL]
|
||||||
When I visit the services page for yaml
|
When I visit the services page for yaml
|
||||||
---
|
---
|
||||||
|
@ -19,16 +19,16 @@ Feature: Page Navigation
|
||||||
---
|
---
|
||||||
When I click [Link] on the navigation
|
When I click [Link] on the navigation
|
||||||
Then the url should be [URL]
|
Then the url should be [URL]
|
||||||
Then the last GET request was made to "[Endpoint]"
|
Then a GET request was made to "[Endpoint]"
|
||||||
Where:
|
Where:
|
||||||
-----------------------------------------------------------------------
|
-------------------------------------------------------------------------------------
|
||||||
| Link | URL | Endpoint |
|
| Link | URL | Endpoint |
|
||||||
| nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 |
|
| nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 |
|
||||||
| kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F |
|
| kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F&ns=@namespace |
|
||||||
| acls | /dc-1/acls/tokens | /v1/acl/tokens?dc=dc-1 |
|
| acls | /dc-1/acls/tokens | /v1/acl/tokens?dc=dc-1&ns=@namespace |
|
||||||
| intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 |
|
| intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 |
|
||||||
# | settings | /settings | /v1/catalog/datacenters |
|
# | settings | /settings | /v1/catalog/datacenters |
|
||||||
-----------------------------------------------------------------------
|
-------------------------------------------------------------------------------------
|
||||||
Scenario: Clicking a [Item] in the [Model] listing and back again
|
Scenario: Clicking a [Item] in the [Model] listing and back again
|
||||||
When I visit the [Model] page for yaml
|
When I visit the [Model] page for yaml
|
||||||
---
|
---
|
||||||
|
@ -40,11 +40,11 @@ Feature: Page Navigation
|
||||||
And I click "[data-test-back]"
|
And I click "[data-test-back]"
|
||||||
Then the url should be [Back]
|
Then the url should be [Back]
|
||||||
Where:
|
Where:
|
||||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
| Item | Model | URL | Endpoint | Back |
|
| Item | Model | URL | Endpoint | Back |
|
||||||
| service | services | /dc-1/services/service-0 | /v1/discovery-chain/service-0?dc=dc-1 | /dc-1/services |
|
| service | services | /dc-1/services/service-0 | /v1/discovery-chain/service-0?dc=dc-1&ns=@namespace | /dc-1/services |
|
||||||
| node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1 | /dc-1/nodes |
|
| node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1&ns=@namespace | /dc-1/nodes |
|
||||||
| kv | kvs | /dc-1/kv/0-key-value/edit | /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1 | /dc-1/kv |
|
| kv | kvs | /dc-1/kv/0-key-value/edit | /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1&ns=@namespace | /dc-1/kv |
|
||||||
# | acl | acls | /dc-1/acls/anonymous | /v1/acl/info/anonymous?dc=dc-1 | /dc-1/acls |
|
# | acl | acls | /dc-1/acls/anonymous | /v1/acl/info/anonymous?dc=dc-1 | /dc-1/acls |
|
||||||
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/internal/ui/services?dc=dc-1&ns=* | /dc-1/intentions |
|
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/internal/ui/services?dc=dc-1&ns=* | /dc-1/intentions |
|
||||||
# These Endpoints will be datacenters due to the datacenters checkbox selectors
|
# These Endpoints will be datacenters due to the datacenters checkbox selectors
|
||||||
|
@ -66,7 +66,7 @@ Feature: Page Navigation
|
||||||
- /v1/namespaces
|
- /v1/namespaces
|
||||||
- /v1/internal/ui/node/node-0?dc=dc-1
|
- /v1/internal/ui/node/node-0?dc=dc-1
|
||||||
- /v1/coordinate/nodes?dc=dc-1
|
- /v1/coordinate/nodes?dc=dc-1
|
||||||
- /v1/session/node/node-0?dc=dc-1
|
- /v1/session/node/node-0?dc=dc-1&ns=@namespace
|
||||||
---
|
---
|
||||||
Scenario: The kv detail page calls the correct API endpoints
|
Scenario: The kv detail page calls the correct API endpoints
|
||||||
When I visit the kv page for yaml
|
When I visit the kv page for yaml
|
||||||
|
@ -79,8 +79,8 @@ Feature: Page Navigation
|
||||||
---
|
---
|
||||||
- /v1/catalog/datacenters
|
- /v1/catalog/datacenters
|
||||||
- /v1/namespaces
|
- /v1/namespaces
|
||||||
- /v1/kv/keyname?dc=dc-1
|
- /v1/kv/keyname?dc=dc-1&ns=@namespace
|
||||||
- /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1
|
- /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1&ns=@namespace
|
||||||
---
|
---
|
||||||
Scenario: The policies page/tab calls the correct API endpoints
|
Scenario: The policies page/tab calls the correct API endpoints
|
||||||
When I visit the policies page for yaml
|
When I visit the policies page for yaml
|
||||||
|
@ -92,7 +92,7 @@ Feature: Page Navigation
|
||||||
---
|
---
|
||||||
- /v1/catalog/datacenters
|
- /v1/catalog/datacenters
|
||||||
- /v1/namespaces
|
- /v1/namespaces
|
||||||
- /v1/acl/policies?dc=dc-1
|
- /v1/acl/policies?dc=dc-1&ns=@namespace
|
||||||
---
|
---
|
||||||
Scenario: The intention detail page calls the correct API endpoints
|
Scenario: The intention detail page calls the correct API endpoints
|
||||||
When I visit the intention page for yaml
|
When I visit the intention page for yaml
|
||||||
|
|
|
@ -3,6 +3,7 @@ Feature: startup
|
||||||
In order to give users an indication as early as possible that they are at the right place
|
In order to give users an indication as early as possible that they are at the right place
|
||||||
As a user
|
As a user
|
||||||
I should be able to see a startup logo
|
I should be able to see a startup logo
|
||||||
|
@notNamespaceable
|
||||||
Scenario: When loading the index.html file into a browser
|
Scenario: When loading the index.html file into a browser
|
||||||
Given 1 datacenter model with the value "dc-1"
|
Given 1 datacenter model with the value "dc-1"
|
||||||
Then the url should be ''
|
Then the url should be ''
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import steps from '../../steps';
|
||||||
|
|
||||||
|
// step definitions that are shared between features should be moved to the
|
||||||
|
// tests/acceptance/steps/steps.js file
|
||||||
|
|
||||||
|
export default function(assert) {
|
||||||
|
return steps(assert).then('I should find a file', function() {
|
||||||
|
assert.ok(true, this.step);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import steps from '../../steps';
|
||||||
|
|
||||||
|
// step definitions that are shared between features should be moved to the
|
||||||
|
// tests/acceptance/steps/steps.js file
|
||||||
|
|
||||||
|
export default function(assert) {
|
||||||
|
return steps(assert).then('I should find a file', function() {
|
||||||
|
assert.ok(true, this.step);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import steps from '../../steps';
|
||||||
|
|
||||||
|
// step definitions that are shared between features should be moved to the
|
||||||
|
// tests/acceptance/steps/steps.js file
|
||||||
|
|
||||||
|
export default function(assert) {
|
||||||
|
return steps(assert).then('I should find a file', function() {
|
||||||
|
assert.ok(true, this.step);
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,91 +1,5 @@
|
||||||
/* eslint no-console: "off", no-control-regex: "off" */
|
|
||||||
import YAML from 'js-yaml';
|
|
||||||
import Inflector from 'ember-inflector';
|
|
||||||
import utils from '@ember/test-helpers';
|
|
||||||
|
|
||||||
import Yadda from 'yadda';
|
|
||||||
import pages from 'consul-ui/tests/pages';
|
|
||||||
import api from 'consul-ui/tests/helpers/api';
|
|
||||||
|
|
||||||
import steps from 'consul-ui/tests/steps';
|
import steps from 'consul-ui/tests/steps';
|
||||||
|
|
||||||
const pluralize = function(str) {
|
export default function({ assert, library }) {
|
||||||
return Inflector.inflector.pluralize(str);
|
return steps(assert, library);
|
||||||
};
|
|
||||||
export default function(assert) {
|
|
||||||
const library = Yadda.localisation.English.library(
|
|
||||||
new Yadda.Dictionary()
|
|
||||||
.define('json', /([^\u0000]*)/, function(val, cb) {
|
|
||||||
cb(null, JSON.parse(val));
|
|
||||||
})
|
|
||||||
.define('yaml', /([^\u0000]*)/, function(val, cb) {
|
|
||||||
cb(null, YAML.safeLoad(val));
|
|
||||||
})
|
|
||||||
.define('model', /(\w+)/, function(model, cb) {
|
|
||||||
switch (model) {
|
|
||||||
case 'datacenter':
|
|
||||||
case 'datacenters':
|
|
||||||
case 'dcs':
|
|
||||||
model = 'dc';
|
|
||||||
break;
|
|
||||||
case 'services':
|
|
||||||
model = 'service';
|
|
||||||
break;
|
|
||||||
case 'nodes':
|
|
||||||
model = 'node';
|
|
||||||
break;
|
|
||||||
case 'kvs':
|
|
||||||
model = 'kv';
|
|
||||||
break;
|
|
||||||
case 'acls':
|
|
||||||
model = 'acl';
|
|
||||||
break;
|
|
||||||
case 'sessions':
|
|
||||||
model = 'session';
|
|
||||||
break;
|
|
||||||
case 'intentions':
|
|
||||||
model = 'intention';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cb(null, model);
|
|
||||||
})
|
|
||||||
.define('number', /(\d+)/, Yadda.converters.integer)
|
|
||||||
);
|
|
||||||
const create = function(number, name, value) {
|
|
||||||
// don't return a promise here as
|
|
||||||
// I don't need it to wait
|
|
||||||
api.server.createList(name, number, value);
|
|
||||||
};
|
|
||||||
const respondWith = function(url, data) {
|
|
||||||
api.server.respondWith(url.split('?')[0], data);
|
|
||||||
};
|
|
||||||
const setCookie = function(key, value) {
|
|
||||||
api.server.setCookie(key, value);
|
|
||||||
};
|
|
||||||
const getLastNthRequest = function(arr) {
|
|
||||||
return function(n, method) {
|
|
||||||
let requests = arr.slice(0).reverse();
|
|
||||||
if (method) {
|
|
||||||
requests = requests.filter(function(item) {
|
|
||||||
return item.method === method;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (n == null) {
|
|
||||||
return requests;
|
|
||||||
}
|
|
||||||
return requests[n];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return steps(assert, library, pages, {
|
|
||||||
pluralize: pluralize,
|
|
||||||
triggerKeyEvent: utils.triggerKeyEvent,
|
|
||||||
currentURL: utils.currentURL,
|
|
||||||
click: utils.click,
|
|
||||||
fillIn: utils.fillIn,
|
|
||||||
find: utils.find,
|
|
||||||
lastNthRequest: getLastNthRequest(api.server.history),
|
|
||||||
respondWith: respondWith,
|
|
||||||
create: create,
|
|
||||||
set: setCookie,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: submit blank
|
Feature: submit-blank
|
||||||
In order to prevent form's being saved without values
|
In order to prevent form's being saved without values
|
||||||
As a user
|
As a user
|
||||||
I shouldn't be able to submit a blank form
|
I shouldn't be able to submit a blank form
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@setupApplicationTest
|
@setupApplicationTest
|
||||||
Feature: token headers
|
@notNamespaceable
|
||||||
|
Feature: token-header
|
||||||
In order to authenticate with tokens
|
In order to authenticate with tokens
|
||||||
As a user
|
As a user
|
||||||
I need to be able to specify a ACL token AND/OR leave it blank to authenticate with the API
|
I need to be able to specify a ACL token AND/OR leave it blank to authenticate with the API
|
||||||
|
@ -7,7 +8,7 @@ Feature: token headers
|
||||||
Given 1 datacenter model with the value "datacenter"
|
Given 1 datacenter model with the value "datacenter"
|
||||||
When I visit the index page
|
When I visit the index page
|
||||||
Then the url should be /datacenter/services
|
Then the url should be /datacenter/services
|
||||||
And a GET request is made to "/v1/namespaces" from yaml
|
And a GET request was made to "/v1/namespaces" from yaml
|
||||||
---
|
---
|
||||||
headers:
|
headers:
|
||||||
X-Consul-Token: ''
|
X-Consul-Token: ''
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* eslint no-control-regex: "off" */
|
||||||
|
import Yadda from 'yadda';
|
||||||
|
import YAML from 'js-yaml';
|
||||||
|
export default function(nspace, dict = new Yadda.Dictionary()) {
|
||||||
|
dict
|
||||||
|
.define('model', /(\w+)/, function(model, cb) {
|
||||||
|
switch (model) {
|
||||||
|
case 'datacenter':
|
||||||
|
case 'datacenters':
|
||||||
|
case 'dcs':
|
||||||
|
model = 'dc';
|
||||||
|
break;
|
||||||
|
case 'services':
|
||||||
|
model = 'service';
|
||||||
|
break;
|
||||||
|
case 'nodes':
|
||||||
|
model = 'node';
|
||||||
|
break;
|
||||||
|
case 'kvs':
|
||||||
|
model = 'kv';
|
||||||
|
break;
|
||||||
|
case 'acls':
|
||||||
|
model = 'acl';
|
||||||
|
break;
|
||||||
|
case 'sessions':
|
||||||
|
model = 'session';
|
||||||
|
break;
|
||||||
|
case 'intentions':
|
||||||
|
model = 'intention';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cb(null, model);
|
||||||
|
})
|
||||||
|
.define('number', /(\d+)/, Yadda.converters.integer)
|
||||||
|
.define('json', /([^\u0000]*)/, function(val, cb) {
|
||||||
|
// replace any instance of @namespace in the string
|
||||||
|
val = val.replace(
|
||||||
|
/@namespace/g,
|
||||||
|
typeof nspace === 'undefined' || nspace === '' ? 'default' : nspace
|
||||||
|
);
|
||||||
|
cb(null, JSON.parse(val));
|
||||||
|
})
|
||||||
|
.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 (typeof nspace === 'undefined' || nspace === '') {
|
||||||
|
val = val.replace(/Namespace: @namespace/g, '').replace(/&ns=@namespace/g, '');
|
||||||
|
}
|
||||||
|
// replace any other instance of @namespace in the string
|
||||||
|
val = val.replace(
|
||||||
|
/@namespace/g,
|
||||||
|
typeof nspace === 'undefined' || nspace === '' ? 'default' : nspace
|
||||||
|
);
|
||||||
|
cb(null, YAML.safeLoad(val));
|
||||||
|
})
|
||||||
|
.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'}`);
|
||||||
|
// for endpoints if namespace isn't specified it should
|
||||||
|
// never add the ns= unless its !important...
|
||||||
|
if (typeof nspace !== 'undefined' && nspace !== '') {
|
||||||
|
val = val.replace(/ns=@namespace/g, `ns=${nspace}`);
|
||||||
|
} else {
|
||||||
|
val = val
|
||||||
|
.replace(/&ns=@namespace/g, '')
|
||||||
|
.replace(/ns=@namespace&/g, '')
|
||||||
|
.replace(/ns=@namespace/g, '');
|
||||||
|
}
|
||||||
|
cb(null, val);
|
||||||
|
});
|
||||||
|
if (typeof nspace !== 'undefined' && nspace !== '') {
|
||||||
|
dict.define('url', /([^\u0000]*)/, function(val, cb) {
|
||||||
|
val = `/~${nspace}${val}`;
|
||||||
|
cb(null, val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
|
@ -42,6 +42,9 @@ export default function(type, value) {
|
||||||
key = 'CONSUL_TOKEN_COUNT';
|
key = 'CONSUL_TOKEN_COUNT';
|
||||||
obj['CONSUL_ACLS_ENABLE'] = 1;
|
obj['CONSUL_ACLS_ENABLE'] = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'nspace':
|
||||||
|
key = 'CONSUL_NSPACE_COUNT';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (key) {
|
if (key) {
|
||||||
obj[key] = value;
|
obj[key] = value;
|
||||||
|
|
|
@ -32,6 +32,9 @@ export default function(type) {
|
||||||
case 'token':
|
case 'token':
|
||||||
requests = ['/v1/acl/tokens', '/v1/acl/token/'];
|
requests = ['/v1/acl/tokens', '/v1/acl/token/'];
|
||||||
break;
|
break;
|
||||||
|
case 'nspace':
|
||||||
|
requests = ['/v1/namespaces', '/v1/namespace/'];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// TODO: An instance of URL should come in here (instead of 2 args)
|
// TODO: An instance of URL should come in here (instead of 2 args)
|
||||||
return function(url, method) {
|
return function(url, method) {
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import ENV from '../../config/environment';
|
import { skip, test } from 'qunit';
|
||||||
import { skip } from 'qunit';
|
import { setupApplicationTest } from 'ember-qunit';
|
||||||
import { setupApplicationTest, setupRenderingTest, setupTest } from 'ember-qunit';
|
import { Promise } from 'rsvp';
|
||||||
import api from 'consul-ui/tests/helpers/api';
|
import Yadda from 'yadda';
|
||||||
|
|
||||||
|
import { env } from '../../env';
|
||||||
|
import api from './api';
|
||||||
|
import getDictionary from '../dictionary';
|
||||||
|
|
||||||
const staticClassList = [...document.documentElement.classList];
|
const staticClassList = [...document.documentElement.classList];
|
||||||
function reset() {
|
const reset = function() {
|
||||||
window.localStorage.clear();
|
window.localStorage.clear();
|
||||||
api.server.reset();
|
api.server.reset();
|
||||||
const list = document.documentElement.classList;
|
const list = document.documentElement.classList;
|
||||||
|
@ -14,84 +18,75 @@ function reset() {
|
||||||
staticClassList.forEach(function(item) {
|
staticClassList.forEach(function(item) {
|
||||||
list.add(item);
|
list.add(item);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
// this logic could be anything, but in this case...
|
|
||||||
// if @ignore, then return skip (for backwards compatibility)
|
const runTest = function(context, libraries, steps, scenarioContext) {
|
||||||
// if have annotations in config, then only run those that have a matching annotation
|
return new Promise((resolve, reject) => {
|
||||||
function checkAnnotations(annotations) {
|
Yadda.Yadda(libraries, context).yadda(steps, scenarioContext, function next(err, result) {
|
||||||
// if ignore is set then we want to skip for backwards compatibility
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const checkAnnotations = function(annotations, isScenario) {
|
||||||
|
annotations = {
|
||||||
|
namespaceable: env('CONSUL_NSPACES_TEST'),
|
||||||
|
...annotations,
|
||||||
|
};
|
||||||
if (annotations.ignore) {
|
if (annotations.ignore) {
|
||||||
return ignoreIt;
|
return function(test) {
|
||||||
|
skip(`${test.title}`, function(assert) {});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
if (isScenario) {
|
||||||
// if have annotations set in config, the only run those that have a matching annotation
|
return function(scenario, feature, yadda, yaddaAnnotations, library) {
|
||||||
if (ENV.annotations && ENV.annotations.length >= 0) {
|
test(`Scenario: ${scenario.title}`, function(assert) {
|
||||||
for (let annotation in annotations) {
|
const libraries = library.default({
|
||||||
if (ENV.annotations.indexOf(annotation) >= 0) {
|
assert: assert,
|
||||||
// have match, so test it
|
library: Yadda.localisation.English.library(getDictionary()),
|
||||||
return 'testIt'; // return something other than a function
|
});
|
||||||
|
const scenarioContext = {
|
||||||
|
ctx: {},
|
||||||
|
};
|
||||||
|
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) {
|
||||||
|
const libraries = library.default({
|
||||||
|
assert: assert,
|
||||||
|
library: Yadda.localisation.English.library(getDictionary(item)),
|
||||||
|
});
|
||||||
|
const scenarioContext = {
|
||||||
|
ctx: {
|
||||||
|
nspace: item,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return runTest(this, libraries, scenario.steps, scenarioContext);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
};
|
||||||
// no match, so don't run it
|
export const setupFeature = function(featureAnnotations) {
|
||||||
return logIt;
|
return setupApplicationTest;
|
||||||
}
|
};
|
||||||
}
|
export const setupScenario = function(featureAnnotations, scenarioAnnotations) {
|
||||||
|
|
||||||
// call back functions
|
|
||||||
function ignoreIt(testElement) {
|
|
||||||
skip(`${testElement.title}`, function(/*assert*/) {});
|
|
||||||
}
|
|
||||||
|
|
||||||
function logIt(testElement) {
|
|
||||||
console.info(`Not running or skipping: "${testElement.title}"`); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
|
|
||||||
// exported functions
|
|
||||||
function runFeature(annotations) {
|
|
||||||
return checkAnnotations(annotations);
|
|
||||||
}
|
|
||||||
|
|
||||||
function runScenario(featureAnnotations, scenarioAnnotations) {
|
|
||||||
return checkAnnotations(scenarioAnnotations);
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup tests
|
|
||||||
// you can override these function to add additional setup setups, or handle new setup related annotations
|
|
||||||
function setupFeature(featureAnnotations) {
|
|
||||||
return setupYaddaTest(featureAnnotations);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupScenario(featureAnnotations, scenarioAnnotations) {
|
|
||||||
let setupFn = setupYaddaTest(scenarioAnnotations);
|
|
||||||
if (
|
|
||||||
setupFn &&
|
|
||||||
(featureAnnotations.setupapplicationtest ||
|
|
||||||
featureAnnotations.setuprenderingtest ||
|
|
||||||
featureAnnotations.setuptest)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
'You must not assign any @setupapplicationtest, @setuprenderingtest or @setuptest annotations to a scenario as well as its feature!'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return function(model) {
|
return function(model) {
|
||||||
model.afterEach(function() {
|
model.afterEach(function() {
|
||||||
reset();
|
reset();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// return setupFn;
|
};
|
||||||
}
|
export const runFeature = function(annotations) {
|
||||||
|
return checkAnnotations(annotations);
|
||||||
|
};
|
||||||
|
|
||||||
function setupYaddaTest(annotations) {
|
export const runScenario = function(featureAnnotations, scenarioAnnotations) {
|
||||||
if (annotations.setupapplicationtest) {
|
return checkAnnotations({ ...featureAnnotations, ...scenarioAnnotations }, true);
|
||||||
return setupApplicationTest;
|
};
|
||||||
}
|
|
||||||
if (annotations.setuprenderingtest) {
|
|
||||||
return setupRenderingTest;
|
|
||||||
}
|
|
||||||
if (annotations.setuptest) {
|
|
||||||
return setupTest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { runFeature, runScenario, setupFeature, setupScenario };
|
|
||||||
|
|
|
@ -43,9 +43,7 @@ module('Integration | Adapter | policy', function(hooks) {
|
||||||
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:policy');
|
const adapter = this.owner.lookup('adapter:policy');
|
||||||
const client = this.owner.lookup('service:client/http');
|
const client = this.owner.lookup('service:client/http');
|
||||||
const expected = `PUT /v1/acl/policy?dc=${dc}${
|
const expected = `PUT /v1/acl/policy?dc=${dc}`;
|
||||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
|
||||||
}`;
|
|
||||||
const actual = adapter
|
const actual = adapter
|
||||||
.requestForCreateRecord(
|
.requestForCreateRecord(
|
||||||
client.url,
|
client.url,
|
||||||
|
@ -62,9 +60,7 @@ module('Integration | Adapter | policy', function(hooks) {
|
||||||
test(`requestForUpdateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
test(`requestForUpdateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:policy');
|
const adapter = this.owner.lookup('adapter:policy');
|
||||||
const client = this.owner.lookup('service:client/http');
|
const client = this.owner.lookup('service:client/http');
|
||||||
const expected = `PUT /v1/acl/policy/${id}?dc=${dc}${
|
const expected = `PUT /v1/acl/policy/${id}?dc=${dc}`;
|
||||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
|
||||||
}`;
|
|
||||||
const actual = adapter
|
const actual = adapter
|
||||||
.requestForUpdateRecord(
|
.requestForUpdateRecord(
|
||||||
client.url,
|
client.url,
|
||||||
|
|
|
@ -36,9 +36,7 @@ module('Integration | Adapter | role', function(hooks) {
|
||||||
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:role');
|
const adapter = this.owner.lookup('adapter:role');
|
||||||
const client = this.owner.lookup('service:client/http');
|
const client = this.owner.lookup('service:client/http');
|
||||||
const expected = `PUT /v1/acl/role?dc=${dc}${
|
const expected = `PUT /v1/acl/role?dc=${dc}`;
|
||||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
|
||||||
}`;
|
|
||||||
const actual = adapter
|
const actual = adapter
|
||||||
.requestForCreateRecord(
|
.requestForCreateRecord(
|
||||||
client.url,
|
client.url,
|
||||||
|
@ -55,9 +53,7 @@ module('Integration | Adapter | role', function(hooks) {
|
||||||
test(`requestForUpdateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
test(`requestForUpdateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:role');
|
const adapter = this.owner.lookup('adapter:role');
|
||||||
const client = this.owner.lookup('service:client/http');
|
const client = this.owner.lookup('service:client/http');
|
||||||
const expected = `PUT /v1/acl/role/${id}?dc=${dc}${
|
const expected = `PUT /v1/acl/role/${id}?dc=${dc}`;
|
||||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
|
||||||
}`;
|
|
||||||
const actual = adapter
|
const actual = adapter
|
||||||
.requestForUpdateRecord(
|
.requestForUpdateRecord(
|
||||||
client.url,
|
client.url,
|
||||||
|
|
|
@ -64,9 +64,7 @@ module('Integration | Adapter | token', function(hooks) {
|
||||||
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:token');
|
const adapter = this.owner.lookup('adapter:token');
|
||||||
const client = this.owner.lookup('service:client/http');
|
const client = this.owner.lookup('service:client/http');
|
||||||
const expected = `PUT /v1/acl/token?dc=${dc}${
|
const expected = `PUT /v1/acl/token?dc=${dc}`;
|
||||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
|
||||||
}`;
|
|
||||||
const actual = adapter
|
const actual = adapter
|
||||||
.requestForCreateRecord(
|
.requestForCreateRecord(
|
||||||
client.url,
|
client.url,
|
||||||
|
@ -83,9 +81,7 @@ module('Integration | Adapter | token', function(hooks) {
|
||||||
test(`requestForUpdateRecord returns the correct url (without Rules it uses the v2 API) when nspace is ${nspace}`, function(assert) {
|
test(`requestForUpdateRecord returns the correct url (without Rules it uses the v2 API) when nspace is ${nspace}`, function(assert) {
|
||||||
const adapter = this.owner.lookup('adapter:token');
|
const adapter = this.owner.lookup('adapter:token');
|
||||||
const client = this.owner.lookup('service:client/http');
|
const client = this.owner.lookup('service:client/http');
|
||||||
const expected = `PUT /v1/acl/token/${id}?dc=${dc}${
|
const expected = `PUT /v1/acl/token/${id}?dc=${dc}`;
|
||||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
|
||||||
}`;
|
|
||||||
const actual = adapter
|
const actual = adapter
|
||||||
.requestForUpdateRecord(
|
.requestForUpdateRecord(
|
||||||
client.url,
|
client.url,
|
||||||
|
|
|
@ -61,7 +61,10 @@ export function visitable(path, encoder = encodeURIComponent) {
|
||||||
return executionContext.runAsync(context => {
|
return executionContext.runAsync(context => {
|
||||||
var params;
|
var params;
|
||||||
let fullPath = (function _try(paths) {
|
let fullPath = (function _try(paths) {
|
||||||
const path = paths.shift();
|
let path = paths.shift();
|
||||||
|
if (typeof dynamicSegmentsAndQueryParams.nspace !== 'undefined') {
|
||||||
|
path = `/:nspace${path}`;
|
||||||
|
}
|
||||||
params = assign({}, dynamicSegmentsAndQueryParams);
|
params = assign({}, dynamicSegmentsAndQueryParams);
|
||||||
var fullPath;
|
var fullPath;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -40,6 +40,8 @@ import tokens from 'consul-ui/tests/pages/dc/acls/tokens/index';
|
||||||
import token from 'consul-ui/tests/pages/dc/acls/tokens/edit';
|
import token from 'consul-ui/tests/pages/dc/acls/tokens/edit';
|
||||||
import intentions from 'consul-ui/tests/pages/dc/intentions/index';
|
import intentions from 'consul-ui/tests/pages/dc/intentions/index';
|
||||||
import intention from 'consul-ui/tests/pages/dc/intentions/edit';
|
import intention from 'consul-ui/tests/pages/dc/intentions/edit';
|
||||||
|
import nspaces from 'consul-ui/tests/pages/dc/nspaces/index';
|
||||||
|
import nspace from 'consul-ui/tests/pages/dc/nspaces/edit';
|
||||||
|
|
||||||
const deletable = createDeletable(clickable);
|
const deletable = createDeletable(clickable);
|
||||||
const submitable = createSubmitable(clickable, is);
|
const submitable = createSubmitable(clickable, is);
|
||||||
|
@ -104,5 +106,9 @@ export default {
|
||||||
intentions(visitable, deletable, creatable, clickable, attribute, collection, intentionFilter)
|
intentions(visitable, deletable, creatable, clickable, attribute, collection, intentionFilter)
|
||||||
),
|
),
|
||||||
intention: create(intention(visitable, submitable, deletable, cancelable)),
|
intention: create(intention(visitable, submitable, deletable, cancelable)),
|
||||||
|
nspaces: create(
|
||||||
|
nspaces(visitable, deletable, creatable, clickable, attribute, collection, text, freetextFilter)
|
||||||
|
),
|
||||||
|
nspace: create(nspace(visitable, submitable, deletable, cancelable)),
|
||||||
settings: create(settings(visitable, submitable)),
|
settings: create(settings(visitable, submitable)),
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
export default function(visitable, submitable, deletable, cancelable) {
|
||||||
|
return {
|
||||||
|
visit: visitable(['/:dc/namespaces/:namespace', '/:dc/namespaces/create']),
|
||||||
|
...submitable({}, 'form > div'),
|
||||||
|
...cancelable({}, 'form > div'),
|
||||||
|
...deletable({}, 'form > div'),
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
export default function(
|
||||||
|
visitable,
|
||||||
|
deletable,
|
||||||
|
creatable,
|
||||||
|
clickable,
|
||||||
|
attribute,
|
||||||
|
collection,
|
||||||
|
text,
|
||||||
|
filter
|
||||||
|
) {
|
||||||
|
return creatable({
|
||||||
|
visit: visitable('/:dc/namespaces'),
|
||||||
|
nspaces: collection(
|
||||||
|
'[data-test-tabular-row]',
|
||||||
|
deletable({
|
||||||
|
action: attribute('data-test-nspace-action', '[data-test-nspace-action]'),
|
||||||
|
description: text('[data-test-description]'),
|
||||||
|
nspace: clickable('a'),
|
||||||
|
actions: clickable('label'),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
filter: filter,
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,3 +1,9 @@
|
||||||
|
import pages from 'consul-ui/tests/pages';
|
||||||
|
import Inflector from 'ember-inflector';
|
||||||
|
import utils from '@ember/test-helpers';
|
||||||
|
|
||||||
|
import api from 'consul-ui/tests/helpers/api';
|
||||||
|
|
||||||
import models from './steps/doubles/model';
|
import models from './steps/doubles/model';
|
||||||
import http from './steps/doubles/http';
|
import http from './steps/doubles/http';
|
||||||
import visit from './steps/interactions/visit';
|
import visit from './steps/interactions/visit';
|
||||||
|
@ -12,16 +18,38 @@ import assertForm from './steps/assertions/form';
|
||||||
|
|
||||||
// const dont = `( don't| shouldn't| can't)?`;
|
// const dont = `( don't| shouldn't| can't)?`;
|
||||||
|
|
||||||
export default function(assert, library, pages, utils) {
|
const pluralize = function(str) {
|
||||||
var currentPage;
|
return Inflector.inflector.pluralize(str);
|
||||||
const getCurrentPage = function() {
|
};
|
||||||
return currentPage;
|
const getLastNthRequest = function(arr) {
|
||||||
|
return function(n, method) {
|
||||||
|
let requests = arr.slice(0).reverse();
|
||||||
|
if (method) {
|
||||||
|
requests = requests.filter(function(item) {
|
||||||
|
return item.method === method;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (n == null) {
|
||||||
|
return requests;
|
||||||
|
}
|
||||||
|
return requests[n];
|
||||||
};
|
};
|
||||||
const setCurrentPage = function(page) {
|
};
|
||||||
currentPage = page;
|
const mb = function(path) {
|
||||||
return page;
|
return function(obj) {
|
||||||
|
return (
|
||||||
|
path.map(function(prop) {
|
||||||
|
obj = obj || {};
|
||||||
|
if (isNaN(parseInt(prop))) {
|
||||||
|
return (obj = obj[prop]);
|
||||||
|
} else {
|
||||||
|
return (obj = obj.objectAt(parseInt(prop)));
|
||||||
|
}
|
||||||
|
}) && obj
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
export default function(assert, library) {
|
||||||
const pauseUntil = function(cb) {
|
const pauseUntil = function(cb) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
@ -38,20 +66,27 @@ export default function(assert, library, pages, utils) {
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const mb = function(path) {
|
const lastNthRequest = getLastNthRequest(api.server.history);
|
||||||
return function(obj) {
|
const create = function(number, name, value) {
|
||||||
return (
|
// don't return a promise here as
|
||||||
path.map(function(prop) {
|
// I don't need it to wait
|
||||||
obj = obj || {};
|
api.server.createList(name, number, value);
|
||||||
if (isNaN(parseInt(prop))) {
|
|
||||||
return (obj = obj[prop]);
|
|
||||||
} else {
|
|
||||||
return (obj = obj.objectAt(parseInt(prop)));
|
|
||||||
}
|
|
||||||
}) && obj
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
const respondWith = function(url, data) {
|
||||||
|
api.server.respondWith(url.split('?')[0], data);
|
||||||
};
|
};
|
||||||
|
const setCookie = function(key, value) {
|
||||||
|
api.server.setCookie(key, value);
|
||||||
|
};
|
||||||
|
let currentPage;
|
||||||
|
const getCurrentPage = function() {
|
||||||
|
return currentPage;
|
||||||
|
};
|
||||||
|
const setCurrentPage = function(page) {
|
||||||
|
currentPage = page;
|
||||||
|
return page;
|
||||||
|
};
|
||||||
|
|
||||||
const find = function(path) {
|
const find = function(path) {
|
||||||
const page = getCurrentPage();
|
const page = getCurrentPage();
|
||||||
const parts = path.split('.');
|
const parts = path.split('.');
|
||||||
|
@ -73,19 +108,23 @@ export default function(assert, library, pages, utils) {
|
||||||
const clipboard = function() {
|
const clipboard = function() {
|
||||||
return window.localStorage.getItem('clipboard');
|
return window.localStorage.getItem('clipboard');
|
||||||
};
|
};
|
||||||
models(library, utils.create);
|
models(library, create);
|
||||||
http(library, utils.respondWith, utils.set);
|
http(library, respondWith, setCookie);
|
||||||
visit(library, pages, setCurrentPage);
|
visit(library, pages, setCurrentPage);
|
||||||
click(library, find, utils.click);
|
click(library, find, utils.click);
|
||||||
form(library, find, utils.fillIn, utils.triggerKeyEvent, getCurrentPage);
|
form(library, find, utils.fillIn, utils.triggerKeyEvent, getCurrentPage);
|
||||||
debug(library, assert, utils.currentURL);
|
debug(library, assert, utils.currentURL);
|
||||||
assertHttp(library, assert, utils.lastNthRequest);
|
assertHttp(library, assert, lastNthRequest);
|
||||||
assertModel(library, assert, find, getCurrentPage, pauseUntil, utils.pluralize);
|
assertModel(library, assert, find, getCurrentPage, pauseUntil, pluralize);
|
||||||
assertPage(library, assert, find, getCurrentPage);
|
assertPage(library, assert, find, getCurrentPage);
|
||||||
assertDom(library, assert, pauseUntil, utils.find, utils.currentURL, clipboard);
|
assertDom(library, assert, pauseUntil, utils.find, utils.currentURL, clipboard);
|
||||||
assertForm(library, assert, find, getCurrentPage);
|
assertForm(library, assert, find, getCurrentPage);
|
||||||
|
|
||||||
return library.given(["I'm using a legacy token"], function(number, model, data) {
|
return library.given(["I'm using a legacy token"], function(number, model, data) {
|
||||||
window.localStorage['consul:token'] = JSON.stringify({ AccessorID: null, SecretID: 'id' });
|
window.localStorage['consul:token'] = JSON.stringify({
|
||||||
|
Namespace: 'default',
|
||||||
|
AccessorID: null,
|
||||||
|
SecretID: 'id',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
// TODO: This entire file/steps need refactoring out so that they don't depend on order
|
|
||||||
// unless you specifically ask it to assert for order of requests
|
|
||||||
// this should also let us simplify the entire API for these steps
|
|
||||||
// an reword them to make more sense
|
|
||||||
export default function(scenario, assert, lastNthRequest) {
|
export default function(scenario, assert, lastNthRequest) {
|
||||||
// lastNthRequest should return a
|
// lastNthRequest should return a
|
||||||
// {
|
// {
|
||||||
|
@ -9,109 +5,7 @@ export default function(scenario, assert, lastNthRequest) {
|
||||||
// requestBody: '',
|
// requestBody: '',
|
||||||
// requestHeaders: ''
|
// requestHeaders: ''
|
||||||
// }
|
// }
|
||||||
const assertRequest = function(request, method, url) {
|
|
||||||
assert.equal(
|
|
||||||
request.method,
|
|
||||||
method,
|
|
||||||
`Expected the request method to be ${method}, was ${request.method}`
|
|
||||||
);
|
|
||||||
assert.equal(request.url, url, `Expected the request url to be ${url}, was ${request.url}`);
|
|
||||||
};
|
|
||||||
scenario
|
scenario
|
||||||
.then('a $method request is made to "$url" with the body from yaml\n$yaml', function(
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
data
|
|
||||||
) {
|
|
||||||
const request = lastNthRequest(1);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
const body = JSON.parse(request.requestBody);
|
|
||||||
Object.keys(data).forEach(function(key, i, arr) {
|
|
||||||
assert.deepEqual(
|
|
||||||
body[key],
|
|
||||||
data[key],
|
|
||||||
`Expected the payload to contain ${key} equaling ${data[key]}, ${key} was ${body[key]}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
// TODO: This one can replace the above one, it covers more use cases
|
|
||||||
// also DRY it out a bit
|
|
||||||
.then('a $method request is made to "$url" from yaml\n$yaml', function(method, url, yaml) {
|
|
||||||
const request = lastNthRequest(1);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
let data = yaml.body || {};
|
|
||||||
const body = JSON.parse(request.requestBody);
|
|
||||||
Object.keys(data).forEach(function(key, i, arr) {
|
|
||||||
assert.equal(
|
|
||||||
body[key],
|
|
||||||
data[key],
|
|
||||||
`Expected the payload to contain ${key} to equal ${body[key]}, ${key} was ${data[key]}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
data = yaml.headers || {};
|
|
||||||
const headers = request.requestHeaders;
|
|
||||||
Object.keys(data).forEach(function(key, i, arr) {
|
|
||||||
assert.equal(
|
|
||||||
headers[key],
|
|
||||||
data[key],
|
|
||||||
`Expected the payload to contain ${key} to equal ${headers[key]}, ${key} was ${data[key]}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then('a $method request is made to "$url" with the body "$body"', function(method, url, data) {
|
|
||||||
const request = lastNthRequest(1);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
assert.equal(
|
|
||||||
request.requestBody,
|
|
||||||
data,
|
|
||||||
`Expected the request body to be ${data}, was ${request.requestBody}`
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.then('a $method request is made to "$url" with no body', function(method, url) {
|
|
||||||
const request = lastNthRequest(1);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
assert.equal(
|
|
||||||
request.requestBody,
|
|
||||||
null,
|
|
||||||
`Expected the request body to be null, was ${request.requestBody}`
|
|
||||||
);
|
|
||||||
})
|
|
||||||
|
|
||||||
.then('a $method request is made to "$url"', function(method, url) {
|
|
||||||
const request = lastNthRequest(1);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
})
|
|
||||||
.then('the last $method request was made to "$url"', function(method, url) {
|
|
||||||
const request = lastNthRequest(0, method);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
})
|
|
||||||
.then('the last $method request was made to "$url" with the body from yaml\n$yaml', function(
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
data
|
|
||||||
) {
|
|
||||||
const request = lastNthRequest(0, method);
|
|
||||||
const body = JSON.parse(request.requestBody);
|
|
||||||
assert.ok(request, `Expected a ${method} request`);
|
|
||||||
assertRequest(request, method, url);
|
|
||||||
Object.keys(data).forEach(function(key, i, arr) {
|
|
||||||
assert.deepEqual(
|
|
||||||
body[key],
|
|
||||||
data[key],
|
|
||||||
`Expected the payload to contain ${key} equaling ${data[key]}, ${key} was ${body[key]}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then('the last $method requests were like yaml\n$yaml', function(method, data) {
|
|
||||||
const requests = lastNthRequest(null, method);
|
|
||||||
data.reverse().forEach(function(item, i, arr) {
|
|
||||||
assert.equal(
|
|
||||||
requests[i].url,
|
|
||||||
item,
|
|
||||||
`Expected the request url to be ${item}, was ${requests[i].url}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then('the last $method requests included from yaml\n$yaml', function(method, data) {
|
.then('the last $method requests included from yaml\n$yaml', function(method, data) {
|
||||||
const requests = lastNthRequest(null, method);
|
const requests = lastNthRequest(null, method);
|
||||||
const a = new Set(data);
|
const a = new Set(data);
|
||||||
|
@ -127,14 +21,40 @@ export default function(scenario, assert, lastNthRequest) {
|
||||||
);
|
);
|
||||||
assert.equal(diff.size, 0, `Expected requests "${[...diff].join(', ')}"`);
|
assert.equal(diff.size, 0, `Expected requests "${[...diff].join(', ')}"`);
|
||||||
})
|
})
|
||||||
.then('a $method request was made to "$url"', function(method, url) {
|
.then('a $method request was made to "$endpoint"', function(method, url) {
|
||||||
const requests = lastNthRequest(null, method);
|
const requests = lastNthRequest(null, method);
|
||||||
const request = requests.find(function(item) {
|
const request = requests.find(function(item) {
|
||||||
return method === item.method && url === item.url;
|
return method === item.method && url === item.url;
|
||||||
});
|
});
|
||||||
assert.ok(request, `Expected a ${method} request url to ${url}`);
|
assert.ok(request, `Expected a ${method} request url to ${url}`);
|
||||||
})
|
})
|
||||||
.then('a $method request was made to "$url" from yaml\n$yaml', function(method, url, yaml) {
|
.then('a $method request was made to "$endpoint" with no body', function(method, url) {
|
||||||
|
const requests = lastNthRequest(null, method);
|
||||||
|
const request = requests.find(function(item) {
|
||||||
|
return method === item.method && url === item.url;
|
||||||
|
});
|
||||||
|
assert.equal(
|
||||||
|
request.requestBody,
|
||||||
|
null,
|
||||||
|
`Expected the request body to be null, was ${request.requestBody}`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then('a $method request was made to "$endpoint" with the body "$body"', function(
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
body
|
||||||
|
) {
|
||||||
|
const requests = lastNthRequest(null, method);
|
||||||
|
const request = requests.find(function(item) {
|
||||||
|
return method === item.method && url === item.url;
|
||||||
|
});
|
||||||
|
assert.ok(request, `Expected a ${method} request url to ${url} with the body "${body}"`);
|
||||||
|
})
|
||||||
|
.then('a $method request was made to "$endpoint" from yaml\n$yaml', function(
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
yaml
|
||||||
|
) {
|
||||||
const requests = lastNthRequest(null, method);
|
const requests = lastNthRequest(null, method);
|
||||||
const request = requests.find(function(item) {
|
const request = requests.find(function(item) {
|
||||||
return method === item.method && url === item.url;
|
return method === item.method && url === item.url;
|
||||||
|
@ -142,19 +62,23 @@ export default function(scenario, assert, lastNthRequest) {
|
||||||
let data = yaml.body || {};
|
let data = yaml.body || {};
|
||||||
const body = JSON.parse(request.requestBody);
|
const body = JSON.parse(request.requestBody);
|
||||||
Object.keys(data).forEach(function(key, i, arr) {
|
Object.keys(data).forEach(function(key, i, arr) {
|
||||||
assert.equal(
|
assert.deepEqual(
|
||||||
body[key],
|
body[key],
|
||||||
data[key],
|
data[key],
|
||||||
`Expected the payload to contain ${key} to equal ${body[key]}, ${key} was ${data[key]}`
|
`Expected the payload to contain ${key} equaling ${JSON.stringify(
|
||||||
|
data[key]
|
||||||
|
)}, ${key} was ${JSON.stringify(body[key])}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
data = yaml.headers || {};
|
data = yaml.headers || {};
|
||||||
const headers = request.requestHeaders;
|
const headers = request.requestHeaders;
|
||||||
Object.keys(data).forEach(function(key, i, arr) {
|
Object.keys(data).forEach(function(key, i, arr) {
|
||||||
assert.equal(
|
assert.deepEqual(
|
||||||
headers[key],
|
headers[key],
|
||||||
data[key],
|
data[key],
|
||||||
`Expected the payload to contain ${key} to equal ${headers[key]}, ${key} was ${data[key]}`
|
`Expected the payload to contain ${key} equaling ${JSON.stringify(
|
||||||
|
data[key]
|
||||||
|
)}, ${key} was ${JSON.stringify(headers[key])}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
export default function(scenario, respondWith, set) {
|
export default function(scenario, respondWith, set) {
|
||||||
// respondWith should set the url to return a certain response shape
|
// respondWith should set the url to return a certain response shape
|
||||||
scenario
|
scenario
|
||||||
.given(['the url "$url" responds with a $status status'], function(url, status) {
|
.given(['the url "$endpoint" responds with a $status status'], function(url, status) {
|
||||||
respondWith(url, {
|
respondWith(url, {
|
||||||
status: parseInt(status),
|
status: parseInt(status),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.given(['the url "$url" responds with from yaml\n$yaml'], function(url, data) {
|
.given(['the url "$endpoint" responds with from yaml\n$yaml'], function(url, data) {
|
||||||
respondWith(url, data);
|
respondWith(url, data);
|
||||||
})
|
})
|
||||||
.given('a network latency of $number', function(number) {
|
.given('a network latency of $number', function(number) {
|
||||||
|
|
|
@ -11,6 +11,10 @@ export default function(scenario, pages, set) {
|
||||||
.when(
|
.when(
|
||||||
['I visit the $name page for yaml\n$yaml', 'I visit the $name page for json\n$json'],
|
['I visit the $name page for yaml\n$yaml', 'I visit the $name page for json\n$json'],
|
||||||
function(name, data) {
|
function(name, data) {
|
||||||
|
const nspace = this.ctx.nspace;
|
||||||
|
if (nspace !== '' && typeof nspace !== 'undefined') {
|
||||||
|
data.nspace = `~${nspace}`;
|
||||||
|
}
|
||||||
// TODO: Consider putting an assertion here for testing the current url
|
// TODO: Consider putting an assertion here for testing the current url
|
||||||
// do I absolutely definitely need that all the time?
|
// do I absolutely definitely need that all the time?
|
||||||
return set(pages[name]).visit(data);
|
return set(pages[name]).visit(data);
|
||||||
|
|
|
@ -34,7 +34,7 @@ module('Unit | Mixin | acl/with actions', function(hooks) {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const item = { ID: 'id' };
|
const item = { ID: 'id' };
|
||||||
const expectedToken = { AccessorID: null, SecretID: item.ID };
|
const expectedToken = { Namespace: 'default', AccessorID: null, SecretID: item.ID };
|
||||||
this.owner.register(
|
this.owner.register(
|
||||||
'service:settings',
|
'service:settings',
|
||||||
Service.extend({
|
Service.extend({
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import nonEmptySet from 'consul-ui/utils/non-empty-set';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Utility | nonEmptySet', function() {
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it works', function(assert) {
|
||||||
|
let result = nonEmptySet();
|
||||||
|
assert.ok(result);
|
||||||
|
});
|
||||||
|
});
|
|
@ -979,9 +979,9 @@
|
||||||
"@glimmer/util" "^0.42.0"
|
"@glimmer/util" "^0.42.0"
|
||||||
|
|
||||||
"@hashicorp/api-double@^1.3.0":
|
"@hashicorp/api-double@^1.3.0":
|
||||||
version "1.6.0"
|
version "1.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/@hashicorp/api-double/-/api-double-1.6.0.tgz#23c48d1982b81b6c9164067354d7653320ba761f"
|
resolved "https://registry.yarnpkg.com/@hashicorp/api-double/-/api-double-1.6.1.tgz#67c4c4c5cbf9f51f3b8bc992ab2df21acf63b318"
|
||||||
integrity sha512-U11NttTVvJUVOFH4bgS8eZ+0s6j4/4DYPz9xkJM2ciZBnG353l2G7LYeivt55QajnCl3ImevEO4vSlvvFf4I4Q==
|
integrity sha512-JkQZIsH/2B9T2oK5SQNDakvqlHjxQHu0I9ftmmrxqkxYvYoLN+Whp7dzQ8HswOp1vIJyqbvUhSw06XfH/eimZA==
|
||||||
dependencies:
|
dependencies:
|
||||||
array-range "^1.0.1"
|
array-range "^1.0.1"
|
||||||
backtick-template "^0.2.0"
|
backtick-template "^0.2.0"
|
||||||
|
@ -3345,9 +3345,9 @@ caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000805, caniuse-lite@^1.0.300009
|
||||||
integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==
|
integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30000844:
|
caniuse-lite@^1.0.30000844:
|
||||||
version "1.0.30001021"
|
version "1.0.30001022"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001021.tgz#e75ed1ef6dbadd580ac7e7720bb16f07b083f254"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz#9eeffe580c3a8f110b7b1742dcf06a395885e4c6"
|
||||||
integrity sha512-wuMhT7/hwkgd8gldgp2jcrUjOU9RXJ4XxGumQeOsUr91l3WwmM68Cpa/ymCnWEDqakwFXhuDQbaKNHXBPgeE9g==
|
integrity sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A==
|
||||||
|
|
||||||
capture-exit@^2.0.0:
|
capture-exit@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
@ -4302,9 +4302,9 @@ electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.30:
|
||||||
integrity sha512-NWJ5TztDnjExFISZHFwpoJjMbLUifsNBnx7u2JI0gCw6SbKyQYYWWtBHasO/jPtHym69F4EZuTpRNGN11MT/jg==
|
integrity sha512-NWJ5TztDnjExFISZHFwpoJjMbLUifsNBnx7u2JI0gCw6SbKyQYYWWtBHasO/jPtHym69F4EZuTpRNGN11MT/jg==
|
||||||
|
|
||||||
electron-to-chromium@^1.3.47:
|
electron-to-chromium@^1.3.47:
|
||||||
version "1.3.335"
|
version "1.3.340"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.335.tgz#5fb6084a25cb1e2542df91e62b62e1931a602303"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f"
|
||||||
integrity sha512-ngKsDGd/xr2lAZvilxTfdvfEiQKmavyXd6irlswaHnewmXoz6JgbM9FUNwgp3NFIUHHegh1F87H8f5BJ8zABxw==
|
integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==
|
||||||
|
|
||||||
elegant-spinner@^1.0.1:
|
elegant-spinner@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
|
@ -9959,9 +9959,9 @@ resolve@^1.1.3, resolve@^1.1.7, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.
|
||||||
path-parse "^1.0.6"
|
path-parse "^1.0.6"
|
||||||
|
|
||||||
resolve@^1.10.0, resolve@^1.3.3:
|
resolve@^1.10.0, resolve@^1.3.3:
|
||||||
version "1.14.2"
|
version "1.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
|
||||||
integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==
|
integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
|
||||||
dependencies:
|
dependencies:
|
||||||
path-parse "^1.0.6"
|
path-parse "^1.0.6"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue