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 { 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()
|
||||
export default Adapter.extend({
|
||||
requestForQuery: function(request, { dc, ns, index, id }) {
|
||||
|
@ -32,7 +35,6 @@ export default Adapter.extend({
|
|||
requestForCreateRecord: function(request, serialized, data) {
|
||||
const params = {
|
||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||
...this.formatNspace(data[NSPACE_KEY]),
|
||||
};
|
||||
return request`
|
||||
PUT /v1/acl/policy?${params}
|
||||
|
@ -42,13 +44,13 @@ export default Adapter.extend({
|
|||
Description: serialized.Description,
|
||||
Rules: serialized.Rules,
|
||||
Datacenters: serialized.Datacenters,
|
||||
...Namespace(serialized.Namespace),
|
||||
}}
|
||||
`;
|
||||
},
|
||||
requestForUpdateRecord: function(request, serialized, data) {
|
||||
const params = {
|
||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||
...this.formatNspace(data[NSPACE_KEY]),
|
||||
};
|
||||
return request`
|
||||
PUT /v1/acl/policy/${data[SLUG_KEY]}?${params}
|
||||
|
@ -58,6 +60,7 @@ export default Adapter.extend({
|
|||
Description: serialized.Description,
|
||||
Rules: serialized.Rules,
|
||||
Datacenters: serialized.Datacenters,
|
||||
Namespace: serialized.Namespace,
|
||||
}}
|
||||
`;
|
||||
},
|
||||
|
|
|
@ -3,7 +3,9 @@ import Adapter from './application';
|
|||
import { SLUG_KEY } from 'consul-ui/models/role';
|
||||
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||
import { NSPACE_KEY } from 'consul-ui/models/nspace';
|
||||
import nonEmptySet from 'consul-ui/utils/non-empty-set';
|
||||
|
||||
const Namespace = nonEmptySet('Namespace');
|
||||
// TODO: Update to use this.formatDatacenter()
|
||||
export default Adapter.extend({
|
||||
requestForQuery: function(request, { dc, ns, index, id }) {
|
||||
|
@ -32,7 +34,6 @@ export default Adapter.extend({
|
|||
requestForCreateRecord: function(request, serialized, data) {
|
||||
const params = {
|
||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||
...this.formatNspace(data[NSPACE_KEY]),
|
||||
};
|
||||
return request`
|
||||
PUT /v1/acl/role?${params}
|
||||
|
@ -40,16 +41,15 @@ export default Adapter.extend({
|
|||
${{
|
||||
Name: serialized.Name,
|
||||
Description: serialized.Description,
|
||||
Namespace: serialized.Namespace,
|
||||
Policies: serialized.Policies,
|
||||
ServiceIdentities: serialized.ServiceIdentities,
|
||||
...Namespace(serialized.Namespace),
|
||||
}}
|
||||
`;
|
||||
},
|
||||
requestForUpdateRecord: function(request, serialized, data) {
|
||||
const params = {
|
||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||
...this.formatNspace(data[NSPACE_KEY]),
|
||||
};
|
||||
return request`
|
||||
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 { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
|
||||
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()
|
||||
export default Adapter.extend({
|
||||
store: service('store'),
|
||||
|
@ -35,7 +37,6 @@ export default Adapter.extend({
|
|||
requestForCreateRecord: function(request, serialized, data) {
|
||||
const params = {
|
||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||
...this.formatNspace(data[NSPACE_KEY]),
|
||||
};
|
||||
return request`
|
||||
PUT /v1/acl/token?${params}
|
||||
|
@ -46,6 +47,7 @@ export default Adapter.extend({
|
|||
Roles: serialized.Roles,
|
||||
ServiceIdentities: serialized.ServiceIdentities,
|
||||
Local: serialized.Local,
|
||||
...Namespace(serialized.Namespace),
|
||||
}}
|
||||
`;
|
||||
},
|
||||
|
@ -66,13 +68,13 @@ export default Adapter.extend({
|
|||
}
|
||||
const params = {
|
||||
...this.formatDatacenter(data[DATACENTER_KEY]),
|
||||
...this.formatNspace(data[NSPACE_KEY]),
|
||||
};
|
||||
return request`
|
||||
PUT /v1/acl/token/${data[SLUG_KEY]}?${params}
|
||||
|
||||
${{
|
||||
Description: serialized.Description,
|
||||
Namespace: serialized.Namespace,
|
||||
Policies: serialized.Policies,
|
||||
Roles: serialized.Roles,
|
||||
ServiceIdentities: serialized.ServiceIdentities,
|
||||
|
|
|
@ -25,7 +25,7 @@ export default Component.extend(SlotsMixin, WithListeners, {
|
|||
this._super(...arguments);
|
||||
this.searchable = this.container.searchable(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() {
|
||||
// It's not massively important here that we are defaulting `items` and
|
||||
|
@ -52,7 +52,7 @@ export default Component.extend(SlotsMixin, WithListeners, {
|
|||
});
|
||||
},
|
||||
reset: function() {
|
||||
this.form.clear({ Datacenter: this.dc });
|
||||
this.form.clear({ Datacenter: this.dc, Namespace: this.nspace });
|
||||
},
|
||||
open: function() {
|
||||
if (!get(this, 'allOptions.closed')) {
|
||||
|
|
|
@ -8,12 +8,14 @@ export default Mixin.create(WithBlockingActions, {
|
|||
actions: {
|
||||
use: function(item) {
|
||||
return this.feedback.execute(() => {
|
||||
// old style legacy ACLs don't have AccessorIDs
|
||||
// therefore set it to null, this way the frontend knows
|
||||
// old style legacy ACLs don't have AccessorIDs or Namespaces
|
||||
// therefore set AccessorID to null, this way the frontend knows
|
||||
// to use legacy ACLs
|
||||
// set the Namespace to just use default
|
||||
return this.settings
|
||||
.persist({
|
||||
token: {
|
||||
Namespace: 'default',
|
||||
AccessorID: null,
|
||||
SecretID: get(item, 'ID'),
|
||||
},
|
||||
|
|
|
@ -16,9 +16,9 @@ export default Route.extend(WithBlockingActions, {
|
|||
return this.settings
|
||||
.persist({
|
||||
token: {
|
||||
Namespace: get(item, 'Namespace'),
|
||||
AccessorID: get(item, 'AccessorID'),
|
||||
SecretID: secret,
|
||||
Namespace: get(item, 'Namespace'),
|
||||
},
|
||||
})
|
||||
.then(item => {
|
||||
|
|
|
@ -15,7 +15,7 @@ export default Route.extend(WithIntentionActions, {
|
|||
},
|
||||
model: function(params) {
|
||||
const dc = this.modelFor('dc').dc.Name;
|
||||
const nspace = this.modelFor('nspace').nspace.substr(1);
|
||||
const nspace = '*';
|
||||
this.item = this.repo.create({
|
||||
Datacenter: dc,
|
||||
});
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
{{#yield-slot name='policy' params=(block-params item)}}
|
||||
{{yield}}
|
||||
{{else}}
|
||||
{{policy-selector dc=dc items=item.Policies}}
|
||||
{{policy-selector dc=dc nspace=nspace items=item.Policies}}
|
||||
{{/yield-slot}}
|
||||
</fieldset>
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
{{#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'}} />
|
||||
{{#role-form form=form dc=dc}}
|
||||
{{#role-form form=form dc=dc nspace=nspace}}
|
||||
{{#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'}}
|
||||
<label for="{{name}}_state_policy" data-test-create-policy class="type-dialog">
|
||||
<span>Create new policy</span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<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))}}
|
||||
<h2>Where is this role used?</h2>
|
||||
<p>
|
||||
|
|
|
@ -23,14 +23,14 @@
|
|||
<p>
|
||||
By adding roles to this namespaces, you will apply them to all tokens created within this namespace.
|
||||
</p>
|
||||
{{role-selector dc=dc items=item.ACLs.RoleDefaults}}
|
||||
{{role-selector dc=dc nspace='default' items=item.ACLs.RoleDefaults}}
|
||||
</fieldset>
|
||||
<fieldset id="policies">
|
||||
<h2>Policies</h2>
|
||||
<p>
|
||||
By adding policies to this namespaces, you will apply them to all tokens created within this namespace.
|
||||
</p>
|
||||
{{policy-selector dc=dc items=item.ACLs.PolicyDefaults}}
|
||||
{{policy-selector dc=dc nspace='default' items=item.ACLs.PolicyDefaults}}
|
||||
</fieldset>
|
||||
{{/if}}
|
||||
<div>
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.nspaces.edit' item.Name}}>Edit</a>
|
||||
</li>
|
||||
{{#if (not-eq item.Name 'default') }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{confirm}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
||||
<div role="menu">
|
||||
|
@ -83,6 +84,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/block-slot}}
|
||||
{{/popover-menu}}
|
||||
{{/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':
|
||||
ENV = Object.assign({}, ENV, {
|
||||
locationType: 'none',
|
||||
CONSUL_NSPACES_TEST: true,
|
||||
CONSUL_ACLS_ENABLED: true,
|
||||
'@hashicorp/ember-cli-api-double': {
|
||||
'auto-import': false,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@setupApplicationTest
|
||||
@notNamespaceable
|
||||
Feature: components / acl filter: Acl Filter
|
||||
In order to find the acl token I'm looking for easier
|
||||
As a user
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: components / intention filter: Intention Filter
|
||||
Feature: components / intention-filter: Intention Filter
|
||||
In order to find the intention I'm looking for easier
|
||||
As a user
|
||||
I should be able to filter by 'policy' (allow/deny) and freetext search tokens by source and destination
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@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
|
||||
As a user
|
||||
I should be redirected to the tokens page
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@setupApplicationTest
|
||||
@notNamespaceable
|
||||
Feature: dc / acls / list-order
|
||||
In order to be able to find ACL tokens easier
|
||||
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 see 2 policy models on the policies component
|
||||
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:
|
||||
- ID: policy-1
|
||||
Name: Policy 1
|
||||
|
|
|
@ -22,18 +22,22 @@ Feature: dc / acls / policies / as many / add new: Add new policy
|
|||
Rules: key {}
|
||||
---
|
||||
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
|
||||
Description: New Policy Description
|
||||
Namespace: @namespace
|
||||
Rules: key {}
|
||||
---
|
||||
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:
|
||||
- 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
|
||||
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 submit on the policies.form
|
||||
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:
|
||||
- ServiceName: New-Service-Identity
|
||||
---
|
||||
|
@ -81,10 +87,11 @@ Feature: dc / acls / policies / as many / add new: Add new policy
|
|||
Rules: key {}
|
||||
---
|
||||
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
|
||||
Description: New Policy Description
|
||||
Namespace: @namespace
|
||||
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:""}'
|
||||
|
|
|
@ -17,13 +17,15 @@ Feature: dc / acls / policies / as many / remove: Remove
|
|||
Then the url should be /datacenter/acls/[Model]s/key
|
||||
And I see 1 policy model on the policies component
|
||||
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 confirmDelete on the policies.selectedOptions
|
||||
And I see 0 policy models on the policies component
|
||||
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: [[]]
|
||||
---
|
||||
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 delete 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 "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 delete 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 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 "success" class
|
||||
When I visit the policy page for yaml
|
||||
|
@ -39,7 +39,7 @@ Feature: dc / acls / policies / delete: Policy Delete
|
|||
dc: datacenter
|
||||
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 confirmDelete on the deleteModal
|
||||
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 datacenter
|
||||
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]
|
||||
Description: [Description]
|
||||
Rules: [Rules]
|
||||
Namespace: @namespace
|
||||
Datacenters:
|
||||
- datacenter
|
||||
|
||||
---
|
||||
Then the url should be /datacenter/acls/policies
|
||||
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
|
||||
---
|
||||
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
|
||||
Roles:
|
||||
- ID: role-1
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / acls / roles / as many / add new: Add new
|
||||
@notNamespaceable
|
||||
Feature: dc / acls / roles / as-many / add-new: Add new
|
||||
Background:
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
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
|
||||
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
|
||||
Namespace: @namespace
|
||||
Description: New Role Description
|
||||
---
|
||||
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
|
||||
Namespace: @namespace
|
||||
Roles:
|
||||
- Name: New-Role
|
||||
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 ".ember-power-select-option:first-child"
|
||||
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
|
||||
Description: New Role Description
|
||||
Namespace: @namespace
|
||||
Policies:
|
||||
- ID: policy-1
|
||||
Name: policy
|
||||
---
|
||||
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
|
||||
Namespace: @namespace
|
||||
Roles:
|
||||
- Name: New-Role
|
||||
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
|
||||
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
|
||||
Description: New Policy Description
|
||||
Namespace: @namespace
|
||||
Rules: key {}
|
||||
---
|
||||
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
|
||||
Description: New Role Description
|
||||
Namespace: @namespace
|
||||
Policies:
|
||||
# TODO: Ouch, we need to do deep partial comparisons here
|
||||
- ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||
Name: New-Policy
|
||||
---
|
||||
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
|
||||
Namespace: @namespace
|
||||
Roles:
|
||||
- Name: New-Role
|
||||
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
|
||||
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
|
||||
Description: New Role Description
|
||||
Namespace: @namespace
|
||||
ServiceIdentities:
|
||||
- ServiceName: New-Service-Identity
|
||||
---
|
||||
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
|
||||
Namespace: @namespace
|
||||
Roles:
|
||||
- Name: New-Role
|
||||
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / acls / roles / as many / list: List
|
||||
Feature: dc / acls / roles / as-many / list: List
|
||||
Scenario:
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And 1 token model from yaml
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / acls / roles / as many / remove: Remove
|
||||
Feature: dc / acls / roles / as-many / remove: Remove
|
||||
Scenario:
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
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 see 0 role models on the roles component
|
||||
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: []
|
||||
---
|
||||
Then the url should be /datacenter/acls/tokens
|
||||
|
|
|
@ -21,8 +21,10 @@ Feature: dc / acls / roles / update: ACL Role Update
|
|||
Description: [Description]
|
||||
---
|
||||
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]
|
||||
Description: [Description]
|
||||
---
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@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:
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
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 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
|
||||
And "[data-notification]" has the "success" class
|
||||
Scenario: Using an ACL token from the detail page
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@setupApplicationTest
|
||||
@notNamespaceable
|
||||
Feature: dc / acls / tokens / legacy / update: ACL Token Update
|
||||
Background:
|
||||
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
|
||||
# And I click "[value=[Type]]"
|
||||
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
|
||||
---
|
||||
body:
|
||||
ID: secret
|
||||
Name: [Name]
|
||||
Type: client
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
@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
|
||||
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
|
||||
---
|
||||
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]"
|
||||
Scenario: I get a 500 error from acl/tokens that is the specific legacy one
|
||||
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
|
||||
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 ".app-view" has the "unauthorized" class
|
||||
@notNamespaceable
|
||||
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 the url "/v1/acl/tokens" responds with from yaml
|
||||
Given the url "/v1/acl/tokens?ns=@namespace" responds with from yaml
|
||||
---
|
||||
status: 500
|
||||
body: "rpc error making call: rpc: can't find method ACL.TokenRead"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@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:
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
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
|
||||
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
|
||||
Then I don't see delete on the tokens
|
||||
|
|
|
@ -19,8 +19,10 @@ Feature: dc / acls / tokens / update: ACL Token Update
|
|||
Description: [Description]
|
||||
---
|
||||
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]
|
||||
---
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@notNamespaceable
|
||||
Feature: dc / acls / update: ACL Update
|
||||
Background:
|
||||
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 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]
|
||||
Type: [Type]
|
||||
---
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@setupApplicationTest
|
||||
@notNamespaceable
|
||||
Feature: dc / acls / use: Using an ACL token
|
||||
Background:
|
||||
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
|
||||
---
|
||||
consul:token: '{"AccessorID":null,"SecretID":"id"}'
|
||||
consul:token: '{"Namespace":"@namespace","AccessorID":null,"SecretID":"id"}'
|
||||
---
|
||||
And I click actions 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
|
||||
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
|
||||
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
|
||||
---
|
||||
consul:token: '{"AccessorID":null,"SecretID":"id"}'
|
||||
consul:token: '{"Namespace":"@namespace","AccessorID":null,"SecretID":"id"}'
|
||||
---
|
||||
And I click use
|
||||
And I click confirmUse
|
||||
|
@ -41,5 +42,5 @@ Feature: dc / acls / use: Using an ACL token
|
|||
And "[data-notification]" has the "success" class
|
||||
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
|
||||
Feature: dc forwarding
|
||||
Feature: dc / forwarding
|
||||
In order to arrive at a useful page when only specifying a dc in the url
|
||||
As a user
|
||||
I should be redirected to the services page for the dc
|
||||
@notNamespaceable
|
||||
Scenario: Arriving at the datacenter index page with no other url info
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
When I visit the dcs page for yaml
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: Datacenters
|
||||
Feature: dc / index: Datacenters
|
||||
@ignore
|
||||
Scenario: Arriving at the service page
|
||||
Given 10 datacenter models
|
||||
|
|
|
@ -32,7 +32,7 @@ Feature: dc / intentions / create: Intention Create
|
|||
# Specifically set deny
|
||||
And I click "[value=deny]"
|
||||
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
|
||||
DestinationName: db
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@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
|
||||
As a user
|
||||
I want to be able to choose see existing services in the dropdown, but not existing proxy services
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@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
|
||||
As a user
|
||||
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 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]
|
||||
Action: [Action]
|
||||
|
|
|
@ -19,12 +19,12 @@ Feature: dc / kvs / sessions / invalidate: Invalidate Lock Sessions
|
|||
Scenario: Invalidating the lock session
|
||||
And I click delete 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
|
||||
And "[data-notification]" has the "notification-deletesession" class
|
||||
And "[data-notification]" has the "success" class
|
||||
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 confirmDelete on the session
|
||||
Then the url should be /datacenter/kv/key/edit
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / kvs / trailing slash
|
||||
Feature: dc / kvs / trailing-slash
|
||||
Scenario: I have 10 folders
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
And 10 kv models from yaml
|
||||
|
@ -9,11 +9,11 @@ Feature: dc / kvs / trailing slash
|
|||
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
|
||||
---
|
||||
dc: 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]
|
||||
---
|
||||
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 "success" class
|
||||
Where:
|
||||
|
@ -50,7 +50,7 @@ Feature: dc / kvs / update: KV Update
|
|||
value: ' '
|
||||
---
|
||||
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
|
||||
And "[data-notification]" has the "notification-update" class
|
||||
And "[data-notification]" has the "success" class
|
||||
|
@ -72,7 +72,7 @@ Feature: dc / kvs / update: KV Update
|
|||
value: ''
|
||||
---
|
||||
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
|
||||
And "[data-notification]" has the "notification-update" 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
|
||||
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
|
||||
And "[data-notification]" has the "notification-update" class
|
||||
And "[data-notification]" has the "success" class
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc > list: List Models
|
||||
Feature: dc / list: List Models
|
||||
Scenario: Listing [Model]
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
And 3 [Model] models
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@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
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
And 5 node models from yaml
|
||||
|
|
|
@ -25,12 +25,12 @@ Feature: dc / nodes / sessions / invalidate: Invalidate Lock Sessions
|
|||
Scenario: Invalidating the lock session
|
||||
And I click delete 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
|
||||
And "[data-notification]" has the "notification-delete" class
|
||||
And "[data-notification]" has the "success" class
|
||||
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 confirmDelete on the sessions
|
||||
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
|
||||
---
|
||||
Then I see the text "404 (Page not found)" in "[data-test-error]"
|
||||
@notNamespaceable
|
||||
Scenario: Arriving at the service page
|
||||
Given 2 datacenter models from yaml
|
||||
---
|
||||
|
@ -23,5 +24,8 @@ Feature: dc / services / error
|
|||
dc: dc-1
|
||||
---
|
||||
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
|
||||
And I see 2 datacenter models
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: dc / services: List Services
|
||||
Feature: dc / services / index: List Services
|
||||
Scenario:
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
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 delete 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 "success" class
|
||||
Where:
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
| Edit | Listing | Method | URL | Data | Slug |
|
||||
# | 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=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: ee52203d-989f-4f7a-ab5a-2bef004164ca |
|
||||
| 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 |
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
| Edit | Listing | Method | URL | Data |
|
||||
| kv | kvs | DELETE | /v1/kv/key-name?dc=datacenter&ns=@!namespace | ["key-name"] |
|
||||
| intention | intentions | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} |
|
||||
| token | tokens | DELETE | /v1/acl/token/001fda31-194e-4ff1-a5ec-589abf2cafd0?dc=datacenter&ns=@!namespace | {"AccessorID": "001fda31-194e-4ff1-a5ec-589abf2cafd0"} |
|
||||
| nspace | nspaces | DELETE | /v1/namespace/a-namespace | {"Name": "a-namespace"} |
|
||||
# | acl | acls | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} |
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Scenario: Deleting a [Model] from the [Model] detail page
|
||||
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 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 "success" class
|
||||
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 "error" class
|
||||
Where:
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
| Model | Method | URL | Slug |
|
||||
# | acl | PUT | /v1/acl/destroy/something?dc=datacenter | acl: something |
|
||||
| kv | DELETE | /v1/kv/key-name?dc=datacenter&ns=default | kv: key-name |
|
||||
| kv | DELETE | /v1/kv/key-name?dc=datacenter&ns=@!namespace | kv: key-name |
|
||||
| intention | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca |
|
||||
| token | DELETE | /v1/acl/token/001fda31-194e-4ff1-a5ec-589abf2cafd0?dc=datacenter&ns=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
|
||||
Scenario: Sort out the wide tables ^
|
||||
Then ok
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@setupApplicationTest
|
||||
Feature: index forwarding
|
||||
@notNamespaceable
|
||||
Feature: index-forwarding
|
||||
Scenario: Arriving at the index page when there is only one datacenter
|
||||
Given 1 datacenter model with the value "datacenter"
|
||||
When I visit the index page
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: Page Navigation
|
||||
Feature: page-navigation
|
||||
In order to view all the data in consul
|
||||
As a user
|
||||
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
|
||||
---
|
||||
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]
|
||||
When I visit the services page for yaml
|
||||
---
|
||||
|
@ -19,16 +19,16 @@ Feature: Page Navigation
|
|||
---
|
||||
When I click [Link] on the navigation
|
||||
Then the url should be [URL]
|
||||
Then the last GET request was made to "[Endpoint]"
|
||||
Then a GET request was made to "[Endpoint]"
|
||||
Where:
|
||||
-----------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------
|
||||
| Link | URL | Endpoint |
|
||||
| nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 |
|
||||
| kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F |
|
||||
| acls | /dc-1/acls/tokens | /v1/acl/tokens?dc=dc-1 |
|
||||
| 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&ns=@namespace |
|
||||
| intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 |
|
||||
# | settings | /settings | /v1/catalog/datacenters |
|
||||
-----------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------
|
||||
Scenario: Clicking a [Item] in the [Model] listing and back again
|
||||
When I visit the [Model] page for yaml
|
||||
---
|
||||
|
@ -40,11 +40,11 @@ Feature: Page Navigation
|
|||
And I click "[data-test-back]"
|
||||
Then the url should be [Back]
|
||||
Where:
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
| Item | Model | URL | Endpoint | Back |
|
||||
| service | services | /dc-1/services/service-0 | /v1/discovery-chain/service-0?dc=dc-1 | /dc-1/services |
|
||||
| node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1 | /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 |
|
||||
| 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&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&ns=@namespace | /dc-1/kv |
|
||||
# | 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 |
|
||||
# These Endpoints will be datacenters due to the datacenters checkbox selectors
|
||||
|
@ -66,7 +66,7 @@ Feature: Page Navigation
|
|||
- /v1/namespaces
|
||||
- /v1/internal/ui/node/node-0?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
|
||||
When I visit the kv page for yaml
|
||||
|
@ -79,8 +79,8 @@ Feature: Page Navigation
|
|||
---
|
||||
- /v1/catalog/datacenters
|
||||
- /v1/namespaces
|
||||
- /v1/kv/keyname?dc=dc-1
|
||||
- /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1
|
||||
- /v1/kv/keyname?dc=dc-1&ns=@namespace
|
||||
- /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1&ns=@namespace
|
||||
---
|
||||
Scenario: The policies page/tab calls the correct API endpoints
|
||||
When I visit the policies page for yaml
|
||||
|
@ -92,7 +92,7 @@ Feature: Page Navigation
|
|||
---
|
||||
- /v1/catalog/datacenters
|
||||
- /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
|
||||
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
|
||||
As a user
|
||||
I should be able to see a startup logo
|
||||
@notNamespaceable
|
||||
Scenario: When loading the index.html file into a browser
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
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';
|
||||
|
||||
const pluralize = function(str) {
|
||||
return Inflector.inflector.pluralize(str);
|
||||
};
|
||||
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,
|
||||
});
|
||||
export default function({ assert, library }) {
|
||||
return steps(assert, library);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@setupApplicationTest
|
||||
Feature: submit blank
|
||||
Feature: submit-blank
|
||||
In order to prevent form's being saved without values
|
||||
As a user
|
||||
I shouldn't be able to submit a blank form
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@setupApplicationTest
|
||||
Feature: token headers
|
||||
@notNamespaceable
|
||||
Feature: token-header
|
||||
In order to authenticate with tokens
|
||||
As a user
|
||||
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"
|
||||
When I visit the index page
|
||||
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:
|
||||
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';
|
||||
obj['CONSUL_ACLS_ENABLE'] = 1;
|
||||
break;
|
||||
case 'nspace':
|
||||
key = 'CONSUL_NSPACE_COUNT';
|
||||
break;
|
||||
}
|
||||
if (key) {
|
||||
obj[key] = value;
|
||||
|
|
|
@ -32,6 +32,9 @@ export default function(type) {
|
|||
case 'token':
|
||||
requests = ['/v1/acl/tokens', '/v1/acl/token/'];
|
||||
break;
|
||||
case 'nspace':
|
||||
requests = ['/v1/namespaces', '/v1/namespace/'];
|
||||
break;
|
||||
}
|
||||
// TODO: An instance of URL should come in here (instead of 2 args)
|
||||
return function(url, method) {
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import ENV from '../../config/environment';
|
||||
import { skip } from 'qunit';
|
||||
import { setupApplicationTest, setupRenderingTest, setupTest } from 'ember-qunit';
|
||||
import api from 'consul-ui/tests/helpers/api';
|
||||
import { skip, test } from 'qunit';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import { Promise } from 'rsvp';
|
||||
import Yadda from 'yadda';
|
||||
|
||||
import { env } from '../../env';
|
||||
import api from './api';
|
||||
import getDictionary from '../dictionary';
|
||||
|
||||
const staticClassList = [...document.documentElement.classList];
|
||||
function reset() {
|
||||
const reset = function() {
|
||||
window.localStorage.clear();
|
||||
api.server.reset();
|
||||
const list = document.documentElement.classList;
|
||||
|
@ -14,84 +18,75 @@ function reset() {
|
|||
staticClassList.forEach(function(item) {
|
||||
list.add(item);
|
||||
});
|
||||
};
|
||||
|
||||
const runTest = function(context, libraries, steps, scenarioContext) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Yadda.Yadda(libraries, context).yadda(steps, scenarioContext, function next(err, result) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
// this logic could be anything, but in this case...
|
||||
// if @ignore, then return skip (for backwards compatibility)
|
||||
// if have annotations in config, then only run those that have a matching annotation
|
||||
function checkAnnotations(annotations) {
|
||||
// if ignore is set then we want to skip for backwards compatibility
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
};
|
||||
const checkAnnotations = function(annotations, isScenario) {
|
||||
annotations = {
|
||||
namespaceable: env('CONSUL_NSPACES_TEST'),
|
||||
...annotations,
|
||||
};
|
||||
if (annotations.ignore) {
|
||||
return ignoreIt;
|
||||
return function(test) {
|
||||
skip(`${test.title}`, function(assert) {});
|
||||
};
|
||||
}
|
||||
|
||||
// if have annotations set in config, the only run those that have a matching annotation
|
||||
if (ENV.annotations && ENV.annotations.length >= 0) {
|
||||
for (let annotation in annotations) {
|
||||
if (ENV.annotations.indexOf(annotation) >= 0) {
|
||||
// have match, so test it
|
||||
return 'testIt'; // return something other than a function
|
||||
if (isScenario) {
|
||||
return function(scenario, feature, yadda, yaddaAnnotations, library) {
|
||||
test(`Scenario: ${scenario.title}`, function(assert) {
|
||||
const libraries = library.default({
|
||||
assert: assert,
|
||||
library: Yadda.localisation.English.library(getDictionary()),
|
||||
});
|
||||
const scenarioContext = {
|
||||
ctx: {},
|
||||
};
|
||||
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
|
||||
return logIt;
|
||||
}
|
||||
}
|
||||
|
||||
// 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!'
|
||||
);
|
||||
}
|
||||
};
|
||||
export const setupFeature = function(featureAnnotations) {
|
||||
return setupApplicationTest;
|
||||
};
|
||||
export const setupScenario = function(featureAnnotations, scenarioAnnotations) {
|
||||
return function(model) {
|
||||
model.afterEach(function() {
|
||||
reset();
|
||||
});
|
||||
};
|
||||
// return setupFn;
|
||||
}
|
||||
};
|
||||
export const runFeature = function(annotations) {
|
||||
return checkAnnotations(annotations);
|
||||
};
|
||||
|
||||
function setupYaddaTest(annotations) {
|
||||
if (annotations.setupapplicationtest) {
|
||||
return setupApplicationTest;
|
||||
}
|
||||
if (annotations.setuprenderingtest) {
|
||||
return setupRenderingTest;
|
||||
}
|
||||
if (annotations.setuptest) {
|
||||
return setupTest;
|
||||
}
|
||||
}
|
||||
|
||||
export { runFeature, runScenario, setupFeature, setupScenario };
|
||||
export const runScenario = function(featureAnnotations, scenarioAnnotations) {
|
||||
return checkAnnotations({ ...featureAnnotations, ...scenarioAnnotations }, true);
|
||||
};
|
||||
|
|
|
@ -43,9 +43,7 @@ module('Integration | Adapter | policy', function(hooks) {
|
|||
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
|
||||
const adapter = this.owner.lookup('adapter:policy');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/acl/policy?dc=${dc}${
|
||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
||||
}`;
|
||||
const expected = `PUT /v1/acl/policy?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForCreateRecord(
|
||||
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) {
|
||||
const adapter = this.owner.lookup('adapter:policy');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/acl/policy/${id}?dc=${dc}${
|
||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
||||
}`;
|
||||
const expected = `PUT /v1/acl/policy/${id}?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForUpdateRecord(
|
||||
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) {
|
||||
const adapter = this.owner.lookup('adapter:role');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/acl/role?dc=${dc}${
|
||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
||||
}`;
|
||||
const expected = `PUT /v1/acl/role?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForCreateRecord(
|
||||
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) {
|
||||
const adapter = this.owner.lookup('adapter:role');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/acl/role/${id}?dc=${dc}${
|
||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
||||
}`;
|
||||
const expected = `PUT /v1/acl/role/${id}?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForUpdateRecord(
|
||||
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) {
|
||||
const adapter = this.owner.lookup('adapter:token');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/acl/token?dc=${dc}${
|
||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
||||
}`;
|
||||
const expected = `PUT /v1/acl/token?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForCreateRecord(
|
||||
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) {
|
||||
const adapter = this.owner.lookup('adapter:token');
|
||||
const client = this.owner.lookup('service:client/http');
|
||||
const expected = `PUT /v1/acl/token/${id}?dc=${dc}${
|
||||
typeof nspace !== 'undefined' ? `&ns=${nspace}` : ``
|
||||
}`;
|
||||
const expected = `PUT /v1/acl/token/${id}?dc=${dc}`;
|
||||
const actual = adapter
|
||||
.requestForUpdateRecord(
|
||||
client.url,
|
||||
|
|
|
@ -61,7 +61,10 @@ export function visitable(path, encoder = encodeURIComponent) {
|
|||
return executionContext.runAsync(context => {
|
||||
var params;
|
||||
let fullPath = (function _try(paths) {
|
||||
const path = paths.shift();
|
||||
let path = paths.shift();
|
||||
if (typeof dynamicSegmentsAndQueryParams.nspace !== 'undefined') {
|
||||
path = `/:nspace${path}`;
|
||||
}
|
||||
params = assign({}, dynamicSegmentsAndQueryParams);
|
||||
var fullPath;
|
||||
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 intentions from 'consul-ui/tests/pages/dc/intentions/index';
|
||||
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 submitable = createSubmitable(clickable, is);
|
||||
|
@ -104,5 +106,9 @@ export default {
|
|||
intentions(visitable, deletable, creatable, clickable, attribute, collection, intentionFilter)
|
||||
),
|
||||
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)),
|
||||
};
|
||||
|
|
|
@ -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 http from './steps/doubles/http';
|
||||
import visit from './steps/interactions/visit';
|
||||
|
@ -12,16 +18,38 @@ import assertForm from './steps/assertions/form';
|
|||
|
||||
// const dont = `( don't| shouldn't| can't)?`;
|
||||
|
||||
export default function(assert, library, pages, utils) {
|
||||
var currentPage;
|
||||
const getCurrentPage = function() {
|
||||
return currentPage;
|
||||
const pluralize = function(str) {
|
||||
return Inflector.inflector.pluralize(str);
|
||||
};
|
||||
const setCurrentPage = function(page) {
|
||||
currentPage = page;
|
||||
return page;
|
||||
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 mb = function(path) {
|
||||
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) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
let count = 0;
|
||||
|
@ -38,20 +66,27 @@ export default function(assert, library, pages, utils) {
|
|||
}, 100);
|
||||
});
|
||||
};
|
||||
const mb = function(path) {
|
||||
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
|
||||
);
|
||||
const lastNthRequest = getLastNthRequest(api.server.history);
|
||||
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);
|
||||
};
|
||||
let currentPage;
|
||||
const getCurrentPage = function() {
|
||||
return currentPage;
|
||||
};
|
||||
const setCurrentPage = function(page) {
|
||||
currentPage = page;
|
||||
return page;
|
||||
};
|
||||
|
||||
const find = function(path) {
|
||||
const page = getCurrentPage();
|
||||
const parts = path.split('.');
|
||||
|
@ -73,19 +108,23 @@ export default function(assert, library, pages, utils) {
|
|||
const clipboard = function() {
|
||||
return window.localStorage.getItem('clipboard');
|
||||
};
|
||||
models(library, utils.create);
|
||||
http(library, utils.respondWith, utils.set);
|
||||
models(library, create);
|
||||
http(library, respondWith, setCookie);
|
||||
visit(library, pages, setCurrentPage);
|
||||
click(library, find, utils.click);
|
||||
form(library, find, utils.fillIn, utils.triggerKeyEvent, getCurrentPage);
|
||||
debug(library, assert, utils.currentURL);
|
||||
assertHttp(library, assert, utils.lastNthRequest);
|
||||
assertModel(library, assert, find, getCurrentPage, pauseUntil, utils.pluralize);
|
||||
assertHttp(library, assert, lastNthRequest);
|
||||
assertModel(library, assert, find, getCurrentPage, pauseUntil, pluralize);
|
||||
assertPage(library, assert, find, getCurrentPage);
|
||||
assertDom(library, assert, pauseUntil, utils.find, utils.currentURL, clipboard);
|
||||
assertForm(library, assert, find, getCurrentPage);
|
||||
|
||||
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) {
|
||||
// lastNthRequest should return a
|
||||
// {
|
||||
|
@ -9,109 +5,7 @@ export default function(scenario, assert, lastNthRequest) {
|
|||
// requestBody: '',
|
||||
// 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
|
||||
.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) {
|
||||
const requests = lastNthRequest(null, method);
|
||||
const a = new Set(data);
|
||||
|
@ -127,14 +21,40 @@ export default function(scenario, assert, lastNthRequest) {
|
|||
);
|
||||
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 request = requests.find(function(item) {
|
||||
return method === item.method && url === item.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 request = requests.find(function(item) {
|
||||
return method === item.method && url === item.url;
|
||||
|
@ -142,19 +62,23 @@ export default function(scenario, assert, lastNthRequest) {
|
|||
let data = yaml.body || {};
|
||||
const body = JSON.parse(request.requestBody);
|
||||
Object.keys(data).forEach(function(key, i, arr) {
|
||||
assert.equal(
|
||||
assert.deepEqual(
|
||||
body[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 || {};
|
||||
const headers = request.requestHeaders;
|
||||
Object.keys(data).forEach(function(key, i, arr) {
|
||||
assert.equal(
|
||||
assert.deepEqual(
|
||||
headers[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) {
|
||||
// respondWith should set the url to return a certain response shape
|
||||
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, {
|
||||
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);
|
||||
})
|
||||
.given('a network latency of $number', function(number) {
|
||||
|
|
|
@ -11,6 +11,10 @@ export default function(scenario, pages, set) {
|
|||
.when(
|
||||
['I visit the $name page for yaml\n$yaml', 'I visit the $name page for json\n$json'],
|
||||
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
|
||||
// do I absolutely definitely need that all the time?
|
||||
return set(pages[name]).visit(data);
|
||||
|
|
|
@ -34,7 +34,7 @@ module('Unit | Mixin | acl/with actions', function(hooks) {
|
|||
})
|
||||
);
|
||||
const item = { ID: 'id' };
|
||||
const expectedToken = { AccessorID: null, SecretID: item.ID };
|
||||
const expectedToken = { Namespace: 'default', AccessorID: null, SecretID: item.ID };
|
||||
this.owner.register(
|
||||
'service:settings',
|
||||
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"
|
||||
|
||||
"@hashicorp/api-double@^1.3.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@hashicorp/api-double/-/api-double-1.6.0.tgz#23c48d1982b81b6c9164067354d7653320ba761f"
|
||||
integrity sha512-U11NttTVvJUVOFH4bgS8eZ+0s6j4/4DYPz9xkJM2ciZBnG353l2G7LYeivt55QajnCl3ImevEO4vSlvvFf4I4Q==
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@hashicorp/api-double/-/api-double-1.6.1.tgz#67c4c4c5cbf9f51f3b8bc992ab2df21acf63b318"
|
||||
integrity sha512-JkQZIsH/2B9T2oK5SQNDakvqlHjxQHu0I9ftmmrxqkxYvYoLN+Whp7dzQ8HswOp1vIJyqbvUhSw06XfH/eimZA==
|
||||
dependencies:
|
||||
array-range "^1.0.1"
|
||||
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==
|
||||
|
||||
caniuse-lite@^1.0.30000844:
|
||||
version "1.0.30001021"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001021.tgz#e75ed1ef6dbadd580ac7e7720bb16f07b083f254"
|
||||
integrity sha512-wuMhT7/hwkgd8gldgp2jcrUjOU9RXJ4XxGumQeOsUr91l3WwmM68Cpa/ymCnWEDqakwFXhuDQbaKNHXBPgeE9g==
|
||||
version "1.0.30001022"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz#9eeffe580c3a8f110b7b1742dcf06a395885e4c6"
|
||||
integrity sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A==
|
||||
|
||||
capture-exit@^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==
|
||||
|
||||
electron-to-chromium@^1.3.47:
|
||||
version "1.3.335"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.335.tgz#5fb6084a25cb1e2542df91e62b62e1931a602303"
|
||||
integrity sha512-ngKsDGd/xr2lAZvilxTfdvfEiQKmavyXd6irlswaHnewmXoz6JgbM9FUNwgp3NFIUHHegh1F87H8f5BJ8zABxw==
|
||||
version "1.3.340"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f"
|
||||
integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==
|
||||
|
||||
elegant-spinner@^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"
|
||||
|
||||
resolve@^1.10.0, resolve@^1.3.3:
|
||||
version "1.14.2"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2"
|
||||
integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
|
||||
integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
|
|
Loading…
Reference in New Issue