ui: Adds Partitions to the HTTP layer (#10447)

This PR mainly adds partition to our HTTP adapter. Additionally and perhaps most importantly, we've also taken the opportunity to move our 'conditional namespaces' deeper into the app.

The reason for doing this was, we like that namespaces should be thought of as required instead of conditional, 'special' things and would like the same thinking to be applied to partitions.

Now, instead of using code throughout the app throughout the adapters to add/remove namespaces or partitions depending on whether they are enabled or not. As a UI engineer you just pretend that namespaces and partitions are always enabled, and we remove them for you deeper in the app, out of the way of you forgetting to treat these properties as a special case.

Notes:

Added a PartitionAbility while we were there (not used as yet)
Started to remove the CONSTANT variables we had just for property names. I prefer that our adapters are as readable and straightforwards as possible, it just looks like HTTP.
We'll probably remove our formatDatacenter method we use also at some point, it was mainly too make it look the same as our previous formatNspace, but now we don't have that, it instead now looks different!
We enable parsing of partition in the UIs URL, but this is feature flagged so still does nothing just yet.
All of the test changes were related to the fact that we were treating client.url as a function rather than a method, and now that we reference this in client.url (etc) it needs binding to client.
This commit is contained in:
John Cowen 2021-09-15 18:09:55 +01:00 committed by GitHub
parent 994d06f363
commit a509655d0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 696 additions and 461 deletions

View File

@ -16,7 +16,7 @@ export default class NspaceAbility extends BaseAbility {
}
get canChoose() {
return this.canUse && this.nspaces.length > 0;
return this.canUse && (this.nspaces || []).length > 0;
}
get canUse() {

View File

@ -0,0 +1,25 @@
import BaseAbility from './base';
import { inject as service } from '@ember/service';
export default class PartitionAbility extends BaseAbility {
@service('env') env;
resource = 'operator';
segmented = false;
get canManage() {
return this.canCreate;
}
get canDelete() {
return this.item.Name !== 'default' && super.canDelete;
}
get canChoose() {
return this.canUse && (this.partitions || []).length > 0;
}
get canUse() {
return this.env.var('CONSUL_PARTITIONS_ENABLED');
}
}

View File

@ -1,18 +1,19 @@
import Adapter from './application';
export default class AuthMethodAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id }) {
requestForQuery(request, { dc, ns, partition, index, id }) {
return request`
GET /v1/acl/auth-methods?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id }) {
requestForQueryRecord(request, { dc, ns, partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -20,7 +21,8 @@ export default class AuthMethodAdapter extends Adapter {
GET /v1/acl/auth-method/${id}?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -1,12 +1,13 @@
import Adapter from './application';
export default class BindingRuleAdapter extends Adapter {
requestForQuery(request, { dc, ns, authmethod, index, id }) {
requestForQuery(request, { dc, ns, partition, authmethod, index, id }) {
return request`
GET /v1/acl/binding-rules?${{ dc, authmethod }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -1,12 +1,15 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default class CoordinateAdapter extends Adapter {
requestForQuery(request, { dc, index, uri }) {
requestForQuery(request, { dc, partition, index, uri }) {
return request`
GET /v1/coordinate/nodes?${{ dc }}
X-Request-ID: ${uri}
${{ index }}
${{
partition,
index,
}}
`;
}
}

View File

@ -2,7 +2,7 @@ import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default class DiscoveryChainAdapter extends Adapter {
requestForQueryRecord(request, { dc, ns, index, id, uri }) {
requestForQueryRecord(request, { dc, ns, partition, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -11,7 +11,8 @@ export default class DiscoveryChainAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -1,6 +1,5 @@
import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './application';
import Adapter from './application';
import { get } from '@ember/object';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
// Intentions have different namespacing to the rest of the UI in that the don't
// have a Namespace property, the DestinationNS is essentially its namespace.
@ -22,7 +21,7 @@ export default class IntentionAdapter extends Adapter {
}
${{
...this.formatNspace('*'),
ns: '*',
index,
filter,
}}
@ -76,7 +75,7 @@ export default class IntentionAdapter extends Adapter {
PUT /v1/connect/intentions/exact?${{
source: `${data.SourceNS}/${data.SourceName}`,
destination: `${data.DestinationNS}/${data.DestinationName}`,
[API_DATACENTER_KEY]: data[DATACENTER_KEY],
dc: data.Datacenter,
}}
${body}
@ -95,7 +94,7 @@ export default class IntentionAdapter extends Adapter {
DELETE /v1/connect/intentions/exact?${{
source: `${data.SourceNS}/${data.SourceName}`,
destination: `${data.DestinationNS}/${data.DestinationName}`,
[API_DATACENTER_KEY]: data[DATACENTER_KEY],
dc: data.Datacenter,
}}
`;
}

View File

@ -2,14 +2,12 @@ import Adapter from './application';
import isFolder from 'consul-ui/utils/isFolder';
import keyToArray from 'consul-ui/utils/keyToArray';
import { SLUG_KEY } from 'consul-ui/models/kv';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
// TODO: Update to use this.formatDatacenter()
const API_KEYS_KEY = 'keys';
export default class KvAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id, separator }) {
requestForQuery(request, { dc, ns, partition, index, id, separator }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -17,13 +15,14 @@ export default class KvAdapter extends Adapter {
GET /v1/kv/${keyToArray(id)}?${{ [API_KEYS_KEY]: null, dc, separator }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id }) {
requestForQueryRecord(request, { dc, ns, partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -31,7 +30,8 @@ export default class KvAdapter extends Adapter {
GET /v1/kv/${keyToArray(id)}?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
@ -41,8 +41,9 @@ export default class KvAdapter extends Adapter {
// https://github.com/hashicorp/consul/issues/3804
requestForCreateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/kv/${keyToArray(data[SLUG_KEY])}?${params}
@ -54,9 +55,10 @@ export default class KvAdapter extends Adapter {
requestForUpdateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
flags: data.Flags,
...this.formatNspace(data[NSPACE_KEY]),
};
return request`
PUT /v1/kv/${keyToArray(data[SLUG_KEY])}?${params}
@ -72,8 +74,9 @@ export default class KvAdapter extends Adapter {
recurse = null;
}
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
recurse,
};
return request`

View File

@ -10,19 +10,20 @@ import Adapter from './application';
// to the node.
export default class NodeAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id, uri }) {
requestForQuery(request, { dc, ns, partition, index, id, uri }) {
return request`
GET /v1/internal/ui/nodes?${{ dc }}
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id, uri }) {
requestForQueryRecord(request, { dc, ns, partition, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -31,7 +32,8 @@ export default class NodeAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -3,29 +3,37 @@ import { SLUG_KEY } from 'consul-ui/models/nspace';
// namespaces aren't categorized by datacenter, therefore no dc
export default class NspaceAdapter extends Adapter {
requestForQuery(request, { index, uri }) {
requestForQuery(request, { partition, index, uri }) {
return request`
GET /v1/namespaces
X-Request-ID: ${uri}
${{ index }}
${{
partition,
index,
}}
`;
}
requestForQueryRecord(request, { index, id }) {
requestForQueryRecord(request, { partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an name');
}
return request`
GET /v1/namespace/${id}
${{ index }}
${{
partition,
index,
}}
`;
}
requestForCreateRecord(request, serialized, data) {
return request`
PUT /v1/namespace/${data[SLUG_KEY]}
PUT /v1/namespace/${data[SLUG_KEY]}?${{
partition: data.Partition,
}}
${{
Name: serialized.Name,
@ -40,7 +48,9 @@ export default class NspaceAdapter extends Adapter {
requestForUpdateRecord(request, serialized, data) {
return request`
PUT /v1/namespace/${data[SLUG_KEY]}
PUT /v1/namespace/${data[SLUG_KEY]}?${{
partition: data.Partition,
}}
${{
Description: serialized.Description,
@ -54,7 +64,9 @@ export default class NspaceAdapter extends Adapter {
requestForDeleteRecord(request, serialized, data) {
return request`
DELETE /v1/namespace/${data[SLUG_KEY]}
DELETE /v1/namespace/${data[SLUG_KEY]}?${{
partition: data.Partition,
}}
`;
}
}

View File

@ -1,47 +1,38 @@
import Adapter from './application';
import { inject as service } from '@ember/service';
import { env } from 'consul-ui/env';
import nonEmptySet from 'consul-ui/utils/non-empty-set';
let Namespace;
if (env('CONSUL_NSPACES_ENABLED')) {
Namespace = nonEmptySet('Namespace');
} else {
Namespace = () => ({});
}
export default class OidcProviderAdapter extends Adapter {
@service('env') env;
requestForQuery(request, { dc, ns, index, uri }) {
requestForQuery(request, { dc, ns, partition, index, uri }) {
return request`
GET /v1/internal/ui/oidc-auth-methods?${{ dc }}
X-Request-ID: ${uri}
${{
ns,
partition,
index,
...this.formatNspace(ns),
}}
`;
}
requestForQueryRecord(request, { dc, ns, id }) {
requestForQueryRecord(request, { dc, ns, partition, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
POST /v1/acl/oidc/auth-url?${{ dc }}
POST /v1/acl/oidc/auth-url?${{ dc, ns, partition }}
Cache-Control: no-store
${{
...Namespace(ns),
AuthMethod: id,
RedirectURI: `${this.env.var('CONSUL_BASE_UI_URL')}/oidc/callback`,
}}
`;
}
requestForAuthorize(request, { dc, ns, id, code, state }) {
requestForAuthorize(request, { dc, ns, partition, id, code, state }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -52,11 +43,10 @@ export default class OidcProviderAdapter extends Adapter {
throw new Error('You must specify an state');
}
return request`
POST /v1/acl/oidc/callback?${{ dc }}
POST /v1/acl/oidc/callback?${{ dc, ns, partition }}
Cache-Control: no-store
${{
...Namespace(ns),
AuthMethod: id,
Code: code,
State: state,

View File

@ -4,16 +4,22 @@ import { inject as service } from '@ember/service';
export default class PermissionAdapter extends Adapter {
@service('env') env;
requestForAuthorize(request, { dc, ns, resources = [], index }) {
requestForAuthorize(request, { dc, ns, partition, resources = [], index }) {
// the authorize endpoint is slightly different to all others in that it
// ignores an ns parameter, but accepts a Namespace property on each
// resource. Here we hide this difference from the rest of the app as
// currently we never need to ask for permissions/resources for multiple
// different namespaces in one call so here we use the ns param and add
// this to the resources instead of passing through on the queryParameter
//
// ^ same goes for Partitions
if (this.env.var('CONSUL_NSPACES_ENABLED')) {
resources = resources.map(item => ({ ...item, Namespace: ns }));
}
if (this.env.var('CONSUL_PARTITIONS_ENABLED')) {
resources = resources.map(item => ({ ...item, Partition: partition }));
}
return request`
POST /v1/internal/acl/authorize?${{ dc, index }}

View File

@ -1,31 +1,21 @@
import Adapter from './application';
import { SLUG_KEY } from 'consul-ui/models/policy';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
import { env } from 'consul-ui/env';
import nonEmptySet from 'consul-ui/utils/non-empty-set';
let Namespace;
if (env('CONSUL_NSPACES_ENABLED')) {
Namespace = nonEmptySet('Namespace');
} else {
Namespace = () => ({});
}
// TODO: Update to use this.formatDatacenter()
export default class PolicyAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id }) {
requestForQuery(request, { dc, ns, partition, index, id }) {
return request`
GET /v1/acl/policies?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id }) {
requestForQueryRecord(request, { dc, ns, partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -33,7 +23,8 @@ export default class PolicyAdapter extends Adapter {
GET /v1/acl/policy/${id}?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
@ -41,7 +32,9 @@ export default class PolicyAdapter extends Adapter {
requestForCreateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/policy?${params}
@ -51,14 +44,15 @@ export default class PolicyAdapter extends Adapter {
Description: serialized.Description,
Rules: serialized.Rules,
Datacenters: serialized.Datacenters,
...Namespace(serialized.Namespace),
}}
`;
}
requestForUpdateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/policy/${data[SLUG_KEY]}?${params}
@ -68,15 +62,15 @@ export default class PolicyAdapter extends Adapter {
Description: serialized.Description,
Rules: serialized.Rules,
Datacenters: serialized.Datacenters,
...Namespace(serialized.Namespace),
}}
`;
}
requestForDeleteRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
DELETE /v1/acl/policy/${data[SLUG_KEY]}?${params}

View File

@ -1,7 +1,7 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default class ProxyAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id, uri }) {
requestForQuery(request, { dc, ns, partition, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -11,7 +11,8 @@ export default class ProxyAdapter extends Adapter {
X-Range: ${id}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -1,31 +1,20 @@
import Adapter from './application';
import { SLUG_KEY } from 'consul-ui/models/role';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
import { env } from 'consul-ui/env';
import nonEmptySet from 'consul-ui/utils/non-empty-set';
let Namespace;
if (env('CONSUL_NSPACES_ENABLED')) {
Namespace = nonEmptySet('Namespace');
} else {
Namespace = () => ({});
}
// TODO: Update to use this.formatDatacenter()
export default class RoleAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id }) {
requestForQuery(request, { dc, ns, partition, index, id }) {
return request`
GET /v1/acl/roles?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id }) {
requestForQueryRecord(request, { dc, ns, partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -33,7 +22,8 @@ export default class RoleAdapter extends Adapter {
GET /v1/acl/role/${id}?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
@ -41,7 +31,9 @@ export default class RoleAdapter extends Adapter {
requestForCreateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/role?${params}
@ -52,14 +44,15 @@ export default class RoleAdapter extends Adapter {
Policies: serialized.Policies,
ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
...Namespace(serialized.Namespace),
}}
`;
}
requestForUpdateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/role/${data[SLUG_KEY]}?${params}
@ -70,15 +63,15 @@ export default class RoleAdapter extends Adapter {
Policies: serialized.Policies,
ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
...Namespace(serialized.Namespace),
}}
`;
}
requestForDeleteRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
DELETE /v1/acl/role/${data[SLUG_KEY]}?${params}

View File

@ -2,7 +2,7 @@ import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default class ServiceInstanceAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id, uri }) {
requestForQuery(request, { dc, ns, partition, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -12,13 +12,14 @@ export default class ServiceInstanceAdapter extends Adapter {
X-Range: ${id}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id, uri }) {
requestForQueryRecord() {
// query and queryRecord both use the same endpoint
// they are just serialized differently
return this.requestForQuery(...arguments);

View File

@ -1,8 +1,7 @@
import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default class ServiceAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, gateway, uri }) {
requestForQuery(request, { dc, ns, partition, index, gateway, uri }) {
if (typeof gateway !== 'undefined') {
return request`
GET /v1/internal/ui/gateway-services-nodes/${gateway}?${{ dc }}
@ -10,7 +9,8 @@ export default class ServiceAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
@ -20,14 +20,15 @@ export default class ServiceAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
}
requestForQueryRecord(request, { dc, ns, index, id, uri }) {
requestForQueryRecord(request, { dc, ns, partition, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -36,7 +37,8 @@ export default class ServiceAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -1,12 +1,10 @@
import Adapter from './application';
import { SLUG_KEY } from 'consul-ui/models/session';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
// TODO: Update to use this.formatDatacenter()
export default class SessionAdapter extends Adapter {
requestForQuery(request, { dc, ns, index, id, uri }) {
requestForQuery(request, { dc, ns, partition, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -15,13 +13,14 @@ export default class SessionAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id }) {
requestForQueryRecord(request, { dc, ns, partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -29,7 +28,8 @@ export default class SessionAdapter extends Adapter {
GET /v1/session/info/${id}?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
@ -37,8 +37,9 @@ export default class SessionAdapter extends Adapter {
requestForDeleteRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/session/destroy/${data[SLUG_KEY]}?${params}

View File

@ -1,34 +1,23 @@
import Adapter from './application';
import { inject as service } from '@ember/service';
import { SLUG_KEY } from 'consul-ui/models/token';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
import { env } from 'consul-ui/env';
import nonEmptySet from 'consul-ui/utils/non-empty-set';
let Namespace;
if (env('CONSUL_NSPACES_ENABLED')) {
Namespace = nonEmptySet('Namespace');
} else {
Namespace = () => ({});
}
// TODO: Update to use this.formatDatacenter()
export default class TokenAdapter extends Adapter {
@service('store') store;
requestForQuery(request, { dc, ns, index, role, policy }) {
requestForQuery(request, { dc, ns, partition, index, role, policy }) {
return request`
GET /v1/acl/tokens?${{ role, policy, dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
}
requestForQueryRecord(request, { dc, ns, index, id }) {
requestForQueryRecord(request, { dc, ns, partition, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -36,7 +25,8 @@ export default class TokenAdapter extends Adapter {
GET /v1/acl/token/${id}?${{ dc }}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;
@ -44,7 +34,9 @@ export default class TokenAdapter extends Adapter {
requestForCreateRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/token?${params}
@ -56,7 +48,6 @@ export default class TokenAdapter extends Adapter {
ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
Local: serialized.Local,
...Namespace(serialized.Namespace),
}}
`;
}
@ -71,13 +62,15 @@ export default class TokenAdapter extends Adapter {
// https://www.consul.io/api/acl/legacy.html#update-acl-token
// as we are using the old API we don't need to specify a nspace
return request`
PUT /v1/acl/update?${this.formatDatacenter(data[DATACENTER_KEY])}
PUT /v1/acl/update?${this.formatDatacenter(data.Datacenter)}
${serialized}
`;
}
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatDatacenter(data.Datacenter),
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/token/${data[SLUG_KEY]}?${params}
@ -89,15 +82,15 @@ export default class TokenAdapter extends Adapter {
ServiceIdentities: serialized.ServiceIdentities,
NodeIdentities: serialized.NodeIdentities,
Local: serialized.Local,
...Namespace(serialized.Namespace),
}}
`;
}
requestForDeleteRecord(request, serialized, data) {
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
};
return request`
DELETE /v1/acl/token/${data[SLUG_KEY]}?${params}
@ -123,8 +116,9 @@ export default class TokenAdapter extends Adapter {
throw new Error('You must specify an id');
}
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
};
return request`
PUT /v1/acl/token/${id}/clone?${params}
@ -158,8 +152,9 @@ export default class TokenAdapter extends Adapter {
// eventually the id is created with this dc value and the id taken from the
// json response of `acls/token/*/clone`
const params = {
...this.formatDatacenter(data[DATACENTER_KEY]),
...this.formatNspace(data[NSPACE_KEY]),
dc: data.Datacenter,
ns: data.Namespace,
partition: data.Partition,
};
return serializer.respondForQueryRecord(respond, params);
},

View File

@ -2,7 +2,7 @@ import Adapter from './application';
// TODO: Update to use this.formatDatacenter()
export default class TopologyAdapter extends Adapter {
requestForQueryRecord(request, { dc, ns, index, id, uri, kind }) {
requestForQueryRecord(request, { dc, ns, partition, kind, index, id, uri }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
@ -11,7 +11,8 @@ export default class TopologyAdapter extends Adapter {
X-Request-ID: ${uri}
${{
...this.formatNspace(ns),
ns,
partition,
index,
}}
`;

View File

@ -1,9 +1,9 @@
import { env } from 'consul-ui/env';
const OPTIONAL = {};
// if (true) {
// OPTIONAL.partition = /^-([a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?)$/;
// }
//
if (env('CONSUL_PARTITIONS_ENABLED')) {
OPTIONAL.partition = /^-([a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?)$/;
}
if (env('CONSUL_NSPACES_ENABLED')) {
OPTIONAL.nspace = /^~([a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?)$/;
}
@ -193,9 +193,9 @@ export default class FSMWithOptionalLocation {
if (typeof hash.nspace !== 'undefined') {
hash.nspace = `~${hash.nspace}`;
}
// if (typeof hash.partition !== 'undefined') {
// hash.partition = `-${hash.partition}`;
// }
if (typeof hash.partition !== 'undefined') {
hash.partition = `-${hash.partition}`;
}
if (typeof this.router === 'undefined') {
this.router = this.container.lookup('router:main');
}

View File

@ -1,5 +1,6 @@
import Serializer from './http';
import { set } from '@ember/object';
import {
HEADERS_SYMBOL as HTTP_HEADERS_SYMBOL,
HEADERS_INDEX as HTTP_HEADERS_INDEX,
@ -11,8 +12,6 @@ import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
import createFingerprinter from 'consul-ui/utils/create-fingerprinter';
const DEFAULT_NSPACE = '';
const map = function(obj, cb) {
if (!Array.isArray(obj)) {
return [obj].map(cb)[0];
@ -26,14 +25,6 @@ const attachHeaders = function(headers, body, query = {}) {
Object.keys(headers).forEach(function(key) {
lower[key.toLowerCase()] = headers[key];
});
// Add a 'pretend' Datacenter/Nspace header, they are not headers the come
// from the request but we add them here so we can use them later for store
// reconciliation
if (typeof query.dc !== 'undefined') {
lower[HTTP_HEADERS_DATACENTER.toLowerCase()] = query.dc;
}
lower[HTTP_HEADERS_NAMESPACE.toLowerCase()] =
typeof query.ns !== 'undefined' ? query.ns : DEFAULT_NSPACE;
//
body[HTTP_HEADERS_SYMBOL] = lower;
return body;
@ -47,7 +38,10 @@ export default class ApplicationSerializer extends Serializer {
return respond((headers, body) =>
attachHeaders(
headers,
map(body, this.fingerprint(this.primaryKey, this.slugKey, query.dc)),
map(
body,
this.fingerprint(this.primaryKey, this.slugKey, query.dc, headers[HTTP_HEADERS_NAMESPACE])
),
query
)
);
@ -55,26 +49,42 @@ export default class ApplicationSerializer extends Serializer {
respondForQueryRecord(respond, query) {
return respond((headers, body) =>
attachHeaders(headers, this.fingerprint(this.primaryKey, this.slugKey, query.dc)(body), query)
attachHeaders(
headers,
this.fingerprint(
this.primaryKey,
this.slugKey,
query.dc,
headers[HTTP_HEADERS_NAMESPACE]
)(body),
query
)
);
}
respondForCreateRecord(respond, serialized, data) {
const slugKey = this.slugKey;
const primaryKey = this.primaryKey;
return respond((headers, body) => {
// If creates are true use the info we already have
if (body === true) {
body = data;
}
// Creates need a primaryKey adding
return this.fingerprint(primaryKey, slugKey, data[DATACENTER_KEY])(body);
return this.fingerprint(
primaryKey,
slugKey,
data[DATACENTER_KEY],
headers[HTTP_HEADERS_NAMESPACE]
)(body);
});
}
respondForUpdateRecord(respond, serialized, data) {
const slugKey = this.slugKey;
const primaryKey = this.primaryKey;
return respond((headers, body) => {
// If updates are true use the info we already have
// TODO: We may aswell avoid re-fingerprinting here if we are just going
@ -85,13 +95,19 @@ export default class ApplicationSerializer extends Serializer {
if (body === true) {
body = data;
}
return this.fingerprint(primaryKey, slugKey, data[DATACENTER_KEY])(body);
return this.fingerprint(
primaryKey,
slugKey,
data[DATACENTER_KEY],
headers[HTTP_HEADERS_NAMESPACE]
)(body);
});
}
respondForDeleteRecord(respond, serialized, data) {
const slugKey = this.slugKey;
const primaryKey = this.primaryKey;
return respond((headers, body) => {
// Deletes only need the primaryKey/uid returning and they need the slug
// key AND potential namespace in order to create the correct
@ -100,7 +116,8 @@ export default class ApplicationSerializer extends Serializer {
[primaryKey]: this.fingerprint(
primaryKey,
slugKey,
data[DATACENTER_KEY]
data[DATACENTER_KEY],
headers[HTTP_HEADERS_NAMESPACE]
)({
[slugKey]: data[slugKey],
[NSPACE_KEY]: data[NSPACE_KEY],

View File

@ -1,8 +1,6 @@
import Serializer from './application';
import { inject as service } from '@ember/service';
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/kv';
import { NSPACE_KEY } from 'consul-ui/models/nspace';
import { NSPACE_QUERY_PARAM as API_NSPACE_KEY } from 'consul-ui/adapters/application';
export default class KvSerializer extends Serializer {
@service('atob') decoder;
@ -32,7 +30,6 @@ export default class KvSerializer extends Serializer {
body.map(item => {
return {
[this.slugKey]: item,
[NSPACE_KEY]: query[API_NSPACE_KEY],
};
})
);

View File

@ -3,7 +3,11 @@ import { get } from '@ember/object';
import { next } from '@ember/runloop';
import { CACHE_CONTROL, CONTENT_TYPE } from 'consul-ui/utils/http/headers';
import { HEADERS_TOKEN as CONSUL_TOKEN } from 'consul-ui/utils/http/consul';
import {
HEADERS_TOKEN as CONSUL_TOKEN,
HEADERS_NAMESPACE as CONSUL_NAMESPACE,
HEADERS_DATACENTER as CONSUL_DATACENTER,
} from 'consul-ui/utils/http/consul';
import createURL from 'consul-ui/utils/http/create-url';
import createHeaders from 'consul-ui/utils/http/create-headers';
@ -26,8 +30,9 @@ export const restartWhenAvailable = function(client) {
throw e;
};
};
const stringifyQueryParams = createQueryParams(encodeURIComponent);
const parseURL = createURL(encodeURIComponent, stringifyQueryParams);
const QueryParams = {
stringify: createQueryParams(encodeURIComponent),
};
const parseHeaders = createHeaders();
const parseBody = function(strs, ...values) {
@ -72,21 +77,34 @@ const parseBody = function(strs, ...values) {
const CLIENT_HEADERS = [CACHE_CONTROL, 'X-Request-ID', 'X-Range', 'Refresh'];
export default class HttpService extends Service {
@service('dom')
dom;
@service('client/connections')
connections;
@service('client/transports/xhr')
transport;
@service('settings')
settings;
@service('dom') dom;
@service('env') env;
@service('client/connections') connections;
@service('client/transports/xhr') transport;
@service('settings') settings;
init() {
super.init(...arguments);
this._listeners = this.dom.listeners();
this.parseURL = createURL(encodeURIComponent, obj => QueryParams.stringify(this.sanitize(obj)));
}
sanitize(obj) {
if (!this.env.var('CONSUL_NSPACES_ENABLED')) {
delete obj.ns;
} else {
if (typeof obj.ns === 'undefined' || obj.ns === null || obj.ns === '') {
delete obj.ns;
}
}
if (!this.env.var('CONSUL_PARTITIONS_ENABLED')) {
delete obj.partition;
} else {
if (typeof obj.partition === 'undefined' || obj.partition === null || obj.partition === '') {
delete obj.partition;
}
}
return obj;
}
willDestroy() {
@ -95,11 +113,13 @@ export default class HttpService extends Service {
}
url() {
return parseURL(...arguments);
return this.parseURL(...arguments);
}
body() {
return parseBody(...arguments);
const res = parseBody(...arguments);
this.sanitize(res[0]);
return res;
}
requestParams(strs, ...values) {
@ -146,7 +166,7 @@ export default class HttpService extends Service {
}
}
} else {
const str = stringifyQueryParams(params.data);
const str = QueryParams.stringify(params.data);
if (str.length > 0) {
if (params.url.indexOf('?') !== -1) {
params.url = `${params.url}&${str}`;
@ -204,6 +224,15 @@ export default class HttpService extends Service {
return prev;
}, {}),
...params.clientHeaders,
// Add a 'pretend' Datacenter/Nspace header, they are not
// headers the come from the request but we add them here so
// we can use them later for store reconciliation.
// Namespace will look at the ns query parameter first,
// followed by the Namespace property of the users token,
// defaulting back to 'default' which will mainly be used in
// OSS
[CONSUL_DATACENTER]: params.data.dc,
[CONSUL_NAMESPACE]: params.data.ns || token.Namespace || 'default',
};
const respond = function(cb) {
return cb(headers, e.data.response);

View File

@ -1,6 +1,7 @@
import { get } from '@ember/object';
export default function(foreignKey, nspaceKey, hash = JSON.stringify) {
return function(primaryKey, slugKey, foreignKeyValue) {
return function(primaryKey, slugKey, foreignKeyValue, nspaceValue) {
if (foreignKeyValue == null || foreignKeyValue.length < 1) {
throw new Error('Unable to create fingerprint, missing foreignKey value');
}
@ -12,17 +13,22 @@ export default function(foreignKey, nspaceKey, hash = JSON.stringify) {
}
return get(item, slugKey);
});
const nspaceValue = get(item, nspaceKey) || 'default';
// This ensures that all data objects have a Namespace value set, even
// in OSS. An empty Namespace will default to default
item[nspaceKey] = nspaceValue;
// in OSS.
if (typeof item[nspaceKey] === 'undefined') {
if (nspaceValue === '*') {
nspaceValue = 'default';
}
item[nspaceKey] = nspaceValue;
}
// console.log(nspaceValue);
// item[nspaceKey] = '*';
if (typeof item[foreignKey] === 'undefined') {
item[foreignKey] = foreignKeyValue;
}
if (typeof item[primaryKey] === 'undefined') {
item[primaryKey] = hash([nspaceValue, foreignKeyValue].concat(slugValues));
item[primaryKey] = hash([item[nspaceKey], foreignKeyValue].concat(slugValues));
}
return item;
};

View File

@ -13,7 +13,11 @@ export default function(parseHeaders, XHR) {
options.complete(this.status);
}
};
xhr.open(options.method, options.url, true);
let url = options.url;
if (url.endsWith('?')) {
url = url.substr(0, url.length - 1);
}
xhr.open(options.method, url, true);
if (typeof options.headers === 'undefined') {
options.headers = {};
}

View File

@ -1,9 +1,8 @@
{
"ID": "${location.pathname.get(3)}",
"Namespace": "${
typeof location.search.ns !== 'undefined' ? location.search.ns :
typeof http.body.Namespace !== 'undefined' ? http.body.Namespace : 'default'
}",
${typeof location.search.ns !== 'undefined' ? `
"Namespace": "${location.search.ns}",
` : ``}
"Description": "${location.pathname.get(3) === '00000000-0000-0000-0000-000000000001' ? 'Built-in Management Policy' : fake.lorem.sentence()}",
${ location.pathname.get(3) !== '00000000-0000-0000-0000-000000000001' ? `
"Datacenters": ${fake.helpers.randomize(['["aq west-5", "ch east-4"]'])},

View File

@ -1,10 +1,9 @@
{
"ID": "${location.pathname.get(3)}",
"Name": "${fake.hacker.noun() + '-role'}",
"Namespace": "${
typeof location.search.ns !== 'undefined' ? location.search.ns :
typeof http.body.Namespace !== 'undefined' ? http.body.Namespace : 'default'
}",
${typeof location.search.ns !== 'undefined' ? `
"Namespace": "${location.search.ns}",
` : ``}
"Description": "${fake.lorem.sentence()}",
"Policies": [
${
@ -50,7 +49,7 @@
return `
{
"NodeName": "${fake.hacker.noun()}",
"Datacenter":"${fake.address.countryCode().toLowerCase()} ${ i % 2 ? "west" : "east"}-${i}"
"Datacenter":"${fake.address.countryCode().toLowerCase()} ${ i % 2 ? "west" : "east"}-${i}"
}
`;
}

View File

@ -2,10 +2,9 @@
"AccessorID": "${location.pathname.get(3)}",
"SecretID":"${fake.random.uuid()}",
"IDPName": "${fake.hacker.noun()}",
"Namespace": "${
typeof location.search.ns !== 'undefined' ? location.search.ns :
typeof http.body.Namespace !== 'undefined' ? http.body.Namespace : 'default'
}",
${typeof location.search.ns !== 'undefined' ? `
"Namespace": "${location.search.ns}",
` : ``}
${ location.pathname.get(3) === '00000000-0000-0000-0000-000000000002' ?
`
"Name": "${fake.hacker.noun()}",

View File

@ -31,14 +31,14 @@ Feature: dc / acls / policies / as many / add existing: Add existing policy
And I click ".ember-power-select-option:first-child"
And I see 2 policy models on the policies component
And I submit
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" with the body from yaml
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter&ns=@!namespace" from yaml
---
Namespace: @namespace
Policies:
- ID: policy-1
Name: Policy 1
- ID: policy-2
Name: Policy 2
body:
Policies:
- ID: policy-1
Name: Policy 1
- ID: policy-2
Name: Policy 2
---
Then the url should be /datacenter/acls/[Model]s
And "[data-notification]" has the "notification-update" class

View File

@ -23,19 +23,17 @@ Feature: dc / acls / policies / as many / add new: Add new policy
Rules: key {}
---
And I click submit on the policies.form
Then a PUT request was made to "/v1/acl/policy?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/policy?dc=datacenter&ns=@namespace" from yaml
---
body:
Name: New-Policy
Description: New Policy Description
Namespace: @namespace
Rules: key {}
---
And I submit
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
Policies:
- ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
Name: New-Policy
@ -57,10 +55,9 @@ 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 was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
ServiceIdentities:
- ServiceName: New-Service-Identity
---
@ -81,10 +78,9 @@ Feature: dc / acls / policies / as many / add new: Add new policy
And I click nodeIdentity on the policies.form
And I click submit on the policies.form
And I submit
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
NodeIdentities:
- NodeName: New-Node-Identity
Datacenter: datacenter
@ -112,12 +108,12 @@ Feature: dc / acls / policies / as many / add new: Add new policy
Rules: key {}
---
And I click submit on the policies.form
Then a 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&ns=@namespace" from yaml
---
Name: New-Policy
Description: New Policy Description
Namespace: @namespace
Rules: key {}
body:
Name: New-Policy
Description: New Policy Description
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:""}'
Where:

View File

@ -25,10 +25,9 @@ Feature: dc / acls / policies / as many / remove: Remove
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 was made to "/v1/acl/[Model]/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/[Model]/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
Policies: [[]]
---
Then the url should be /datacenter/acls/[Model]s

View File

@ -17,11 +17,10 @@ Feature: dc / acls / policies / create
Description: [Description]
---
And I submit
Then a PUT request was made to "/v1/acl/policy?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/policy?dc=datacenter&ns=@namespace" from yaml
---
body:
Name: my-policy
Namespace: @namespace
Description: [Description]
---
Then the url should be /datacenter/acls/policies

View File

@ -26,13 +26,12 @@ Feature: dc / acls / policies / update: ACL Policy Update
And I click validDatacenters
And I click datacenter
And I submit
Then a PUT request was made to "/v1/acl/policy/policy-id?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/policy/policy-id?dc=datacenter&ns=@!namespace" from yaml
---
body:
Name: [Name]
Description: [Description]
Rules: [Rules]
Namespace: @namespace
Datacenters:
- datacenter

View File

@ -35,10 +35,9 @@ Feature: dc / acls / roles / as many / add existing: Add existing
Description: The Description
---
And I submit
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
Description: The Description
Roles:
- ID: role-1

View File

@ -30,19 +30,17 @@ Feature: dc / acls / roles / as-many / add-new: Add new
---
Scenario: Add Policy-less Role
And I click submit on the roles.form
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/role?dc=datacenter&ns=@namespace" from yaml
---
body:
Name: New-Role
Namespace: @namespace
Description: New Role Description
---
And I submit
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@namespace" from yaml
---
body:
Description: The Description
Namespace: @namespace
Roles:
- Name: New-Role
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
@ -54,22 +52,20 @@ Feature: dc / acls / roles / as-many / add-new: Add new
And I click "#new-role .ember-power-select-trigger"
And I click ".ember-power-select-option:first-child"
And I click submit on the roles.form
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/role?dc=datacenter&ns=@namespace" 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 was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@namespace" from yaml
---
body:
Description: The Description
Namespace: @namespace
Roles:
- Name: New-Role
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
@ -87,32 +83,29 @@ 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 a PUT request was made to "/v1/acl/policy?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/policy?dc=datacenter&ns=@namespace" from yaml
---
body:
Name: New-Policy
Description: New Policy Description
Namespace: @namespace
Rules: key {}
---
And I click submit on the roles.form
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/role?dc=datacenter&ns=@namespace" 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 was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@namespace" from yaml
---
body:
Description: The Description
Namespace: @namespace
Roles:
- Name: New-Role
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1
@ -130,21 +123,19 @@ 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 a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/role?dc=datacenter&ns=@namespace" from yaml
---
body:
Name: New-Role
Description: New Role Description
Namespace: @namespace
ServiceIdentities:
- ServiceName: New-Service-Identity
---
And I submit
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@namespace" from yaml
---
body:
Description: The Description
Namespace: @namespace
Roles:
- Name: New-Role
ID: ee52203d-989f-4f7a-ab5a-2bef004164ca-1

View File

@ -21,10 +21,9 @@ 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 was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
Roles: []
---
Then the url should be /datacenter/acls/tokens

View File

@ -17,10 +17,9 @@ Feature: dc / acls / roles / create
Description: [Description]
---
And I submit
Then a PUT request was made to "/v1/acl/role?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/role?dc=datacenter&ns=@namespace" from yaml
---
body:
Namespace: @namespace
Name: my-role
Description: [Description]
---

View File

@ -22,10 +22,9 @@ Feature: dc / acls / roles / update: ACL Role Update
Description: [Description]
---
And I submit
Then a PUT request was made to "/v1/acl/role/role-id?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/role/role-id?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
Name: [Name]
Description: [Description]
---

View File

@ -15,10 +15,9 @@ Feature: dc / acls / tokens / create
Description: [Description]
---
And I submit
Then a PUT request was made to "/v1/acl/token?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token?dc=datacenter&ns=@namespace" from yaml
---
body:
Namespace: @namespace
Description: [Description]
---
Then the url should be /datacenter/acls/tokens

View File

@ -6,6 +6,7 @@ Feature: dc / acls / tokens / own-no-delete: The your current token has no delet
---
AccessorID: token
SecretID: ee52203d-989f-4f7a-ab5a-2bef004164ca
Namespace: @!namespace
---
Scenario: On the listing page
Given settings from yaml

View File

@ -20,10 +20,9 @@ Feature: dc / acls / tokens / update: ACL Token Update
Description: [Description]
---
And I submit
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter" from yaml
Then a PUT request was made to "/v1/acl/token/key?dc=datacenter&ns=@!namespace" from yaml
---
body:
Namespace: @namespace
Description: [Description]
---
Then the url should be /datacenter/acls/tokens

View File

@ -6,6 +6,7 @@ Feature: dc / acls / tokens / use: Using an ACL token
---
AccessorID: token
SecretID: ee52203d-989f-4f7a-ab5a-2bef004164ca
Namespace: @!namespace
---
And settings from yaml
---

View File

@ -24,7 +24,7 @@ Feature: dc / kvs / sessions / invalidate: Invalidate Lock Sessions
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/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter&ns=@!namespace" 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

View File

@ -22,7 +22,7 @@ Feature: dc / kvs / update: KV Update
value: [Value]
---
And I submit
Then a PUT request was made to "/v1/kv/[EncodedName]?dc=datacenter&flags=12&ns=@!namespace" with the body "[Value]"
Then a PUT request was made to "/v1/kv/[EncodedName]?dc=datacenter&ns=@!namespace&flags=12" with the body "[Value]"
And "[data-notification]" has the "notification-update" class
And "[data-notification]" has the "success" class
Where:
@ -53,7 +53,7 @@ Feature: dc / kvs / update: KV Update
value: ' '
---
And I submit
Then a PUT request was made to "/v1/kv/key?dc=datacenter&flags=12&ns=@!namespace" with the body " "
Then a PUT request was made to "/v1/kv/key?dc=datacenter&ns=@!namespace&flags=12" with the body " "
Then the url should be /datacenter/kv
And the title should be "Key/Value - Consul"
And "[data-notification]" has the "notification-update" class
@ -77,7 +77,7 @@ Feature: dc / kvs / update: KV Update
value: ''
---
And I submit
Then a PUT request was made to "/v1/kv/key?dc=datacenter&flags=12&ns=@!namespace" with no body
Then a PUT request was made to "/v1/kv/key?dc=datacenter&ns=@!namespace&flags=12" 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
@ -95,7 +95,7 @@ Feature: dc / kvs / update: KV Update
---
Then the url should be /datacenter/kv/key/edit
And I submit
Then a PUT request was made to "/v1/kv/key?dc=datacenter&flags=12&ns=@!namespace" with no body
Then a PUT request was made to "/v1/kv/key?dc=datacenter&ns=@!namespace&flags=12" 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

View File

@ -30,7 +30,7 @@ Feature: dc / nodes / sessions / invalidate: Invalidate Lock Sessions
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=@!namespace" 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/lock-sessions

View File

@ -50,10 +50,12 @@ export default utils => (annotations, nspace, dict = new Yadda.Dictionary()) =>
// mainly for DELETEs
if (env('CONSUL_NSPACES_ENABLED')) {
val = val.replace(/ns=@!namespace/g, `ns=${nspace || 'default'}`);
val = val.replace(/Namespace: @!namespace/g, `Namespace: ${nspace || 'default'}`);
} else {
val = val.replace(/&ns=@!namespace/g, '');
val = val.replace(/&ns=\*/g, '');
val = val.replace(/- \/v1\/namespaces/g, '');
val = val.replace(/Namespace: @!namespace/g, '');
}
if (typeof nspace === 'undefined' || nspace === '') {
val = val.replace(/Namespace: @namespace/g, '').replace(/&ns=@namespace/g, '');

View File

@ -20,13 +20,15 @@ const stubAdapterResponse = function(cb, payload, adapter) {
set(adapter, 'client', {
request: function(cb) {
return cb(function() {
const params = client.requestParams(...arguments);
payload.headers['X-Consul-Namespace'] = params.data.ns || 'default';
return Promise.resolve(function(cb) {
return cb({}, payloadClone);
return cb(payload.headers, payloadClone.payload);
});
});
},
});
return cb(payload).then(function(result) {
return cb(payload.payload).then(function(result) {
set(adapter, 'client', client);
return result;
});
@ -61,6 +63,11 @@ export default function(name, method, service, stub, test, assert) {
headers: {
cookie: cookies,
},
}).then(function(payload) {
return {
headers: {},
payload: payload,
};
});
};
const parseResponse = function(response) {

View File

@ -7,8 +7,9 @@ module('Integration | Adapter | acl', function(hooks) {
test('requestForQuery returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `GET /v1/acl/list?dc=${dc}`;
const actual = adapter.requestForQuery(client.url, {
const actual = adapter.requestForQuery(request, {
dc: dc,
});
assert.equal(actual, expected);
@ -16,8 +17,9 @@ module('Integration | Adapter | acl', function(hooks) {
test('requestForQueryRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `GET /v1/acl/info/${id}?dc=${dc}`;
const actual = adapter.requestForQueryRecord(client.url, {
const actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
});
@ -26,8 +28,9 @@ module('Integration | Adapter | acl', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -35,10 +38,11 @@ module('Integration | Adapter | acl', function(hooks) {
test('requestForCreateRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/acl/create?dc=${dc}`;
const actual = adapter
.requestForCreateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -51,10 +55,11 @@ module('Integration | Adapter | acl', function(hooks) {
test('requestForUpdateRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/acl/update?dc=${dc}`;
const actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -67,10 +72,11 @@ module('Integration | Adapter | acl', function(hooks) {
test('requestForDeleteRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/acl/destroy/${id}?dc=${dc}`;
const actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -83,10 +89,11 @@ module('Integration | Adapter | acl', function(hooks) {
test('requestForCloneRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:acl');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/acl/clone/${id}?dc=${dc}`;
const actual = adapter
.requestForCloneRecord(
client.url,
request,
{},
{
Datacenter: dc,

View File

@ -10,8 +10,9 @@ module('Integration | Adapter | auth-method', function(hooks) {
test('requestForQueryRecord returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:auth-method');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/acl/auth-method/${id}?dc=${dc}`;
const actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
const actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
});
@ -20,8 +21,9 @@ module('Integration | Adapter | auth-method', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:auth-method');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -29,7 +31,8 @@ module('Integration | Adapter | auth-method', function(hooks) {
test('requestForQueryRecord returns the correct body', function(assert) {
return nspaceRunner(
(adapter, serializer, client) => {
return adapter.requestForQueryRecord(client.body, {
const request = client.body.bind(client);
return adapter.requestForQueryRecord(request, {
id: id,
dc: dc,
ns: 'team-1',

View File

@ -9,8 +9,9 @@ module('Integration | Adapter | binding-rule', function(hooks) {
test('requestForQuery returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:binding-rule');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/acl/binding-rules?dc=${dc}`;
const actual = adapter.requestForQuery(client.requestParams.bind(client), {
const actual = adapter.requestForQuery(request, {
dc: dc,
});
assert.equal(`${actual.method} ${actual.url}`, expected);
@ -18,7 +19,8 @@ module('Integration | Adapter | binding-rule', function(hooks) {
test('requestForQuery returns the correct body', function(assert) {
return nspaceRunner(
(adapter, serializer, client) => {
return adapter.requestForQuery(client.body, {
const request = client.body.bind(client);
return adapter.requestForQuery(request, {
dc: dc,
ns: 'team-1',
index: 1,

View File

@ -6,8 +6,9 @@ module('Integration | Adapter | coordinate', function(hooks) {
test('requestForQuery returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:coordinate');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/coordinate/nodes?dc=${dc}`;
const actual = adapter.requestForQuery(client.requestParams.bind(client), {
const actual = adapter.requestForQuery(request, {
dc: dc,
});
assert.equal(`${actual.method} ${actual.url}`, expected);
@ -15,10 +16,11 @@ module('Integration | Adapter | coordinate', function(hooks) {
test('requestForQuery returns the correct body', function(assert) {
const adapter = this.owner.lookup('adapter:coordinate');
const client = this.owner.lookup('service:client/http');
const request = client.body.bind(client);
const expected = {
index: 1,
};
const [actual] = adapter.requestForQuery(client.body, {
const [actual] = adapter.requestForQuery(request, {
dc: dc,
index: 1,
});

View File

@ -5,8 +5,9 @@ module('Integration | Adapter | dc', function(hooks) {
test('requestForQuery returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:dc');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `GET /v1/catalog/datacenters`;
const actual = adapter.requestForQuery(client.url);
const actual = adapter.requestForQuery(request);
assert.equal(actual, expected);
});
});

View File

@ -10,8 +10,9 @@ module('Integration | Adapter | discovery-chain', function(hooks) {
test('requestForQueryRecord returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:discovery-chain');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/discovery-chain/${id}?dc=${dc}`;
const actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
const actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
});
@ -20,8 +21,9 @@ module('Integration | Adapter | discovery-chain', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:discovery-chain');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -29,7 +31,8 @@ module('Integration | Adapter | discovery-chain', function(hooks) {
test('requestForQueryRecord returns the correct body', function(assert) {
return nspaceRunner(
(adapter, serializer, client) => {
return adapter.requestForQueryRecord(client.body, {
const request = client.body.bind(client);
return adapter.requestForQueryRecord(request, {
id: id,
dc: dc,
ns: 'team-1',

View File

@ -11,7 +11,8 @@ module('Integration | Adapter | intention', function(hooks) {
test('requestForQuery returns the correct url', function(assert) {
return nspaceRunner(
(adapter, serializer, client) => {
return adapter.requestForQuery(client.body, {
const request = client.body.bind(client);
return adapter.requestForQuery(request, {
dc: dc,
ns: 'team-1',
filter: '*',
@ -34,9 +35,10 @@ module('Integration | Adapter | intention', function(hooks) {
test('requestForQueryRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:intention');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `GET /v1/connect/intentions/exact?source=SourceNS%2FSourceName&destination=DestinationNS%2FDestinationName&dc=${dc}`;
const actual = adapter
.requestForQueryRecord(client.url, {
.requestForQueryRecord(request, {
dc: dc,
id: id,
})
@ -46,8 +48,9 @@ module('Integration | Adapter | intention', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:intention');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -55,10 +58,11 @@ module('Integration | Adapter | intention', function(hooks) {
test('requestForCreateRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:intention');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/connect/intentions/exact?source=SourceNS%2FSourceName&destination=DestinationNS%2FDestinationName&dc=${dc}`;
const actual = adapter
.requestForCreateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -74,10 +78,11 @@ module('Integration | Adapter | intention', function(hooks) {
test('requestForUpdateRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:intention');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/connect/intentions/exact?source=SourceNS%2FSourceName&destination=DestinationNS%2FDestinationName&dc=${dc}`;
const actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -93,10 +98,11 @@ module('Integration | Adapter | intention', function(hooks) {
test('requestForDeleteRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:intention');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `DELETE /v1/connect/intentions/exact?source=SourceNS%2FSourceName&destination=DestinationNS%2FDestinationName&dc=${dc}`;
const actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,

View File

@ -13,10 +13,11 @@ module('Integration | Adapter | kv', function(hooks) {
test(`requestForQuery returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/kv/${id}?keys&dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
id: id,
ns: nspace,
@ -26,10 +27,11 @@ module('Integration | Adapter | kv', function(hooks) {
test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/kv/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -39,12 +41,13 @@ module('Integration | Adapter | kv', function(hooks) {
test(`requestForCreateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/kv/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter
.requestForCreateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -60,13 +63,14 @@ module('Integration | Adapter | kv', function(hooks) {
test(`requestForUpdateRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const flags = 12;
const expected = `PUT /v1/kv/${id}?dc=${dc}&flags=${flags}${
const expected = `PUT /v1/kv/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
}&flags=${flags}`;
let actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -83,12 +87,13 @@ module('Integration | Adapter | kv', function(hooks) {
test(`requestForDeleteRecord returns the correct url/method when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `DELETE /v1/kv/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -103,13 +108,14 @@ module('Integration | Adapter | kv', function(hooks) {
test(`requestForDeleteRecord returns the correct url/method for folders when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const folder = `${id}/`;
const expected = `DELETE /v1/kv/${folder}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}&recurse`;
let actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -125,8 +131,9 @@ module('Integration | Adapter | kv', function(hooks) {
test("requestForQuery throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQuery(client.url, {
adapter.requestForQuery(request, {
dc: dc,
});
});
@ -134,8 +141,9 @@ module('Integration | Adapter | kv', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:kv');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});

View File

@ -13,10 +13,11 @@ module('Integration | Adapter | node', function(hooks) {
test(`requestForQuery returns the correct url when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:node');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/internal/ui/nodes?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter.requestForQuery(client.requestParams.bind(client), {
const actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
});
@ -25,10 +26,11 @@ module('Integration | Adapter | node', function(hooks) {
test(`requestForQueryRecord returns the correct url when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:node');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/internal/ui/node/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
const actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -40,8 +42,9 @@ module('Integration | Adapter | node', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:node');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -49,8 +52,9 @@ module('Integration | Adapter | node', function(hooks) {
test('requestForQueryLeader returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:node');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/status/leader?dc=${dc}`;
const actual = adapter.requestForQueryLeader(client.requestParams.bind(client), {
const actual = adapter.requestForQueryLeader(request, {
dc: dc,
});
assert.equal(`${actual.method} ${actual.url}`, expected);

View File

@ -8,15 +8,17 @@ module('Integration | Adapter | nspace', function(hooks) {
test('requestForQuery returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:nspace');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/namespaces`;
const actual = adapter.requestForQuery(client.requestParams.bind(client), {});
const actual = adapter.requestForQuery(request, {});
assert.equal(`${actual.method} ${actual.url}`, expected);
});
test('requestForQueryRecord returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:nspace');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `GET /v1/namespace/${id}`;
const actual = adapter.requestForQueryRecord(client.url, {
const actual = adapter.requestForQueryRecord(request, {
id: id,
});
assert.equal(actual, expected);
@ -24,8 +26,9 @@ module('Integration | Adapter | nspace', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:nspace');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {});
adapter.requestForQueryRecord(request, {});
});
});
});

View File

@ -14,10 +14,11 @@ module('Integration | Adapter | oidc-provider', function(hooks) {
test('requestForQuery returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:oidc-provider');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/internal/ui/oidc-auth-methods?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
});
@ -26,9 +27,12 @@ module('Integration | Adapter | oidc-provider', function(hooks) {
test('requestForQueryRecord returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:oidc-provider');
const client = this.owner.lookup('service:client/http');
const expected = `POST /v1/acl/oidc/auth-url?dc=${dc}`;
const request = client.url.bind(client);
const expected = `POST /v1/acl/oidc/auth-url?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForQueryRecord(client.url, {
.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -40,8 +44,9 @@ module('Integration | Adapter | oidc-provider', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:oidc-provider');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -49,9 +54,12 @@ module('Integration | Adapter | oidc-provider', function(hooks) {
test('requestForAuthorize returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:oidc-provider');
const client = this.owner.lookup('service:client/http');
const expected = `POST /v1/acl/oidc/callback?dc=${dc}`;
const request = client.url.bind(client);
const expected = `POST /v1/acl/oidc/callback?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForAuthorize(client.url, {
.requestForAuthorize(request, {
dc: dc,
id: id,
code: 'code',
@ -65,9 +73,10 @@ module('Integration | Adapter | oidc-provider', function(hooks) {
test('requestForLogout returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:oidc-provider');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `POST /v1/acl/logout`;
const actual = adapter
.requestForLogout(client.url, {
.requestForLogout(request, {
id: id,
})
.split('\n')

View File

@ -13,11 +13,12 @@ module('Integration | Adapter | permission', function(hooks) {
test('requestForAuthorize returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:permission');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
// authorize endpoint doesn't need an ns sending on the query param
const expected = `POST /v1/internal/acl/authorize?dc=${dc}${
shouldHaveNspace(nspace) ? `` : ``
}`;
const actual = adapter.requestForAuthorize(client.requestParams.bind(client), {
const actual = adapter.requestForAuthorize(request, {
dc: dc,
ns: nspace,
});

View File

@ -9,8 +9,9 @@ module('Integration | Adapter | policy', function(hooks) {
skip('urlForTranslateRecord returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:policy');
const client = this.owner.lookup('service:client/http');
const request = client.id.bind(client);
const expected = `GET /v1/acl/policy/translate`;
const actual = adapter.requestForTranslateRecord(client.id, {});
const actual = adapter.requestForTranslateRecord(request, {});
assert.equal(actual, expected);
});
const dc = 'dc-1';
@ -20,10 +21,11 @@ module('Integration | Adapter | policy', function(hooks) {
test(`requestForQuery 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 request = client.requestParams.bind(client);
const expected = `GET /v1/acl/policies?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
});
@ -32,10 +34,11 @@ module('Integration | Adapter | policy', function(hooks) {
test(`requestForQueryRecord 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 request = client.requestParams.bind(client);
const expected = `GET /v1/acl/policy/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -45,10 +48,13 @@ 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}`;
const request = client.url.bind(client);
const expected = `PUT /v1/acl/policy?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForCreateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -62,10 +68,13 @@ 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}`;
const request = client.url.bind(client);
const expected = `PUT /v1/acl/policy/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -80,12 +89,13 @@ module('Integration | Adapter | policy', function(hooks) {
test(`requestForDeleteRecord returns the correct url/method when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:policy');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `DELETE /v1/acl/policy/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -101,8 +111,9 @@ module('Integration | Adapter | policy', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:policy');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});

View File

@ -13,10 +13,11 @@ module('Integration | Adapter | role', function(hooks) {
test(`requestForQuery 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 request = client.requestParams.bind(client);
const expected = `GET /v1/acl/roles?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
});
@ -25,10 +26,11 @@ module('Integration | Adapter | role', function(hooks) {
test(`requestForQueryRecord 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 request = client.requestParams.bind(client);
const expected = `GET /v1/acl/role/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -38,10 +40,13 @@ 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}`;
const request = client.url.bind(client);
const expected = `PUT /v1/acl/role?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForCreateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -55,10 +60,13 @@ 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}`;
const request = client.url.bind(client);
const expected = `PUT /v1/acl/role/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -73,12 +81,13 @@ module('Integration | Adapter | role', function(hooks) {
test(`requestForDeleteRecord returns the correct url/method when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:role');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `DELETE /v1/acl/role/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -94,8 +103,9 @@ module('Integration | Adapter | role', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:role');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});

View File

@ -13,10 +13,11 @@ module('Integration | Adapter | service-instance', function(hooks) {
test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:service-instance');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/health/service/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -27,8 +28,9 @@ module('Integration | Adapter | service-instance', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:service-instance');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});

View File

@ -13,10 +13,11 @@ module('Integration | Adapter | service', function(hooks) {
test(`requestForQuery returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:service');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/internal/ui/services?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
});
@ -25,11 +26,12 @@ module('Integration | Adapter | service', function(hooks) {
test(`requestForQuery returns the correct url/method when called with gateway when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:service');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const gateway = 'gateway';
const expected = `GET /v1/internal/ui/gateway-services-nodes/${gateway}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
gateway: gateway,
@ -39,10 +41,11 @@ module('Integration | Adapter | service', function(hooks) {
test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:service');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/health/service/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -53,8 +56,9 @@ module('Integration | Adapter | service', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:service');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});

View File

@ -13,11 +13,12 @@ module('Integration | Adapter | session', function(hooks) {
test(`requestForQuery returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:session');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const node = 'node-id';
const expected = `GET /v1/session/node/${node}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
id: node,
ns: nspace,
@ -27,10 +28,11 @@ module('Integration | Adapter | session', function(hooks) {
test(`requestForQueryRecord returns the correct url/method when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:session');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/session/info/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -40,12 +42,13 @@ module('Integration | Adapter | session', function(hooks) {
test(`requestForDeleteRecord returns the correct url/method when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:session');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/session/destroy/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -61,8 +64,9 @@ module('Integration | Adapter | session', function(hooks) {
test("requestForQuery throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:session');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQuery(client.url, {
adapter.requestForQuery(request, {
dc: dc,
});
});
@ -70,8 +74,9 @@ module('Integration | Adapter | session', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:session');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});

View File

@ -13,10 +13,11 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForQuery 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 request = client.requestParams.bind(client);
const expected = `GET /v1/acl/tokens?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
ns: nspace,
});
@ -25,10 +26,11 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForQuery returns the correct url/method when a policy is specified when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/acl/tokens?policy=${id}&dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
policy: id,
ns: nspace,
@ -38,10 +40,11 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForQuery returns the correct url/method when a role is specified when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/acl/tokens?role=${id}&dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQuery(client.requestParams.bind(client), {
let actual = adapter.requestForQuery(request, {
dc: dc,
role: id,
ns: nspace,
@ -51,10 +54,11 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForQueryRecord 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 request = client.requestParams.bind(client);
const expected = `GET /v1/acl/token/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
let actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
ns: nspace,
@ -64,10 +68,13 @@ 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}`;
const request = client.url.bind(client);
const expected = `PUT /v1/acl/token?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForCreateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -81,10 +88,13 @@ 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}`;
const request = client.url.bind(client);
const expected = `PUT /v1/acl/token/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -99,10 +109,13 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForUpdateRecord returns the correct url (with Rules it uses the v1 API) when nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
// As the title of the test says, this one uses the ACL legacy APIs and
// therefore does not expect a nspace
const expected = `PUT /v1/acl/update?dc=${dc}`;
const actual = adapter
.requestForUpdateRecord(
client.url,
request,
{},
{
Rules: 'key {}',
@ -118,12 +131,13 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForDeleteRecord returns the correct url/method when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `DELETE /v1/acl/token/${id}?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForDeleteRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -138,12 +152,13 @@ module('Integration | Adapter | token', function(hooks) {
test(`requestForCloneRecord returns the correct url when the nspace is ${nspace}`, function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `PUT /v1/acl/token/${id}/clone?dc=${dc}${
shouldHaveNspace(nspace) ? `&ns=${nspace}` : ``
}`;
const actual = adapter
.requestForCloneRecord(
client.url,
request,
{},
{
Datacenter: dc,
@ -159,8 +174,9 @@ module('Integration | Adapter | token', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -168,10 +184,11 @@ module('Integration | Adapter | token', function(hooks) {
test('requestForSelf returns the correct url', function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const expected = `GET /v1/acl/token/self?dc=${dc}`;
const actual = adapter
.requestForSelf(
client.url,
request,
{},
{
dc: dc,
@ -183,11 +200,12 @@ module('Integration | Adapter | token', function(hooks) {
test('requestForSelf sets a token header using a secret', function(assert) {
const adapter = this.owner.lookup('adapter:token');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
const secret = 'sssh';
const expected = `X-Consul-Token: ${secret}`;
const actual = adapter
.requestForSelf(
client.url,
request,
{},
{
dc: dc,

View File

@ -11,8 +11,9 @@ module('Integration | Adapter | topology', function(hooks) {
test('requestForQueryRecord returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:topology');
const client = this.owner.lookup('service:client/http');
const request = client.requestParams.bind(client);
const expected = `GET /v1/internal/ui/service-topology/${id}?dc=${dc}&kind=${kind}`;
const actual = adapter.requestForQueryRecord(client.requestParams.bind(client), {
const actual = adapter.requestForQueryRecord(request, {
dc: dc,
id: id,
kind: kind,
@ -22,8 +23,9 @@ module('Integration | Adapter | topology', function(hooks) {
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:topology');
const client = this.owner.lookup('service:client/http');
const request = client.url.bind(client);
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
adapter.requestForQueryRecord(request, {
dc: dc,
});
});
@ -31,7 +33,8 @@ module('Integration | Adapter | topology', function(hooks) {
test('requestForQueryRecord returns the correct body', function(assert) {
return nspaceRunner(
(adapter, serializer, client) => {
return adapter.requestForQueryRecord(client.body, {
const request = client.body.bind(client);
return adapter.requestForQueryRecord(request, {
id: id,
dc: dc,
ns: 'team-1',

View File

@ -28,7 +28,9 @@ module('Integration | Serializer | acl', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},
@ -49,7 +51,7 @@ module('Integration | Serializer | acl', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: '',
[NSPACE.toLowerCase()]: nspace,
},
// TODO: default isn't required here, once we've
// refactored out our Serializer this can go
@ -58,7 +60,10 @@ module('Integration | Serializer | acl', function(hooks) {
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -27,13 +27,16 @@ module('Integration | Serializer | auth-method', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
{
dc: dc,
ns: nspace,
ns: nspace || undefinedNspace,
}
);
assert.deepEqual(actual, expected);
@ -51,14 +54,17 @@ module('Integration | Serializer | auth-method', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload.Namespace || undefinedNspace,
uid: `["${payload.Namespace || undefinedNspace}","${dc}","${id}"]`,
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -1,6 +1,7 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { get } from 'consul-ui/tests/helpers/api';
import { HEADERS_DATACENTER as DC, HEADERS_NAMESPACE as NSPACE } from 'consul-ui/utils/http/consul';
module('Integration | Serializer | coordinate', function(hooks) {
setupTest(hooks);
const dc = 'dc-1';
@ -22,7 +23,10 @@ module('Integration | Serializer | coordinate', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -2,7 +2,11 @@ import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { get } from 'consul-ui/tests/helpers/api';
import { HEADERS_SYMBOL as META } from 'consul-ui/utils/http/consul';
import {
HEADERS_SYMBOL as META,
HEADERS_DATACENTER as DC,
HEADERS_NAMESPACE as NSPACE,
} from 'consul-ui/utils/http/consul';
module('Integration | Serializer | discovery-chain', function(hooks) {
setupTest(hooks);
@ -10,6 +14,7 @@ module('Integration | Serializer | discovery-chain', function(hooks) {
const serializer = this.owner.lookup('serializer:discovery-chain');
const dc = 'dc-1';
const id = 'slug';
const nspace = 'default';
const request = {
url: `/v1/discovery-chain/${id}?dc=${dc}`,
};
@ -17,11 +22,14 @@ module('Integration | Serializer | discovery-chain', function(hooks) {
const expected = {
Datacenter: dc,
[META]: {},
uid: `["default","${dc}","${id}"]`,
uid: `["${nspace}","${dc}","${id}"]`,
};
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -28,7 +28,10 @@ module('Integration | Serializer | intention', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},
@ -70,7 +73,10 @@ module('Integration | Serializer | intention', function(hooks) {
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -35,7 +35,10 @@ module('Integration | Serializer | kv', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
@ -57,20 +60,23 @@ module('Integration | Serializer | kv', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload[0].Namespace || undefinedNspace,
uid: `["${payload[0].Namespace || undefinedNspace}","${dc}","${id}"]`,
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
{
dc: dc,
ns: nspace,
ns: nspace || undefinedNspace,
id: id,
}
);

View File

@ -21,7 +21,10 @@ module('Integration | Serializer | node', function(hooks) {
return get(request.url).then(function(payload) {
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},
@ -51,7 +54,10 @@ module('Integration | Serializer | node', function(hooks) {
return get(request.url).then(function(payload) {
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},
@ -80,12 +86,15 @@ module('Integration | Serializer | node', function(hooks) {
Port: '8500',
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: '',
[NSPACE.toLowerCase()]: nspace,
},
};
const actual = serializer.respondForQueryLeader(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -28,7 +28,10 @@ module('Integration | Serializer | oidc-provider', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
@ -58,14 +61,17 @@ module('Integration | Serializer | oidc-provider', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: nspace || undefinedNspace,
uid: `["${nspace || undefinedNspace}","${dc}","${id}"]`,
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -27,7 +27,10 @@ module('Integration | Serializer | policy', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
@ -49,14 +52,17 @@ module('Integration | Serializer | policy', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload.Namespace || undefinedNspace,
uid: `["${payload.Namespace || undefinedNspace}","${dc}","${id}"]`,
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -30,7 +30,10 @@ module('Integration | Serializer | role', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
@ -53,14 +56,17 @@ module('Integration | Serializer | role', function(hooks) {
Policies: createPolicies(payload),
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload.Namespace || undefinedNspace,
uid: `["${payload.Namespace || undefinedNspace}","${dc}","${id}"]`,
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -28,14 +28,17 @@ module('Integration | Serializer | service-instance', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload[0].Service.Namespace || undefinedNspace,
uid: `["${payload[0].Service.Namespace || undefinedNspace}","${dc}","${node}","${id}"]`,
};
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -1,6 +1,7 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { get } from 'consul-ui/tests/helpers/api';
import { HEADERS_DATACENTER as DC, HEADERS_NAMESPACE as NSPACE } from 'consul-ui/utils/http/consul';
module('Integration | Serializer | service', function(hooks) {
setupTest(hooks);
const dc = 'dc-1';
@ -23,7 +24,10 @@ module('Integration | Serializer | service', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -30,7 +30,10 @@ module('Integration | Serializer | session | response', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
@ -54,14 +57,17 @@ module('Integration | Serializer | session | response', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload[0].Namespace || undefinedNspace,
uid: `["${payload[0].Namespace || undefinedNspace}","${dc}","${id}"]`,
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -31,7 +31,10 @@ module('Integration | Serializer | token', function(hooks) {
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},
@ -53,7 +56,7 @@ module('Integration | Serializer | token', function(hooks) {
Datacenter: dc,
[META]: {
[DC.toLowerCase()]: dc,
[NSPACE.toLowerCase()]: nspace || '',
[NSPACE.toLowerCase()]: nspace || undefinedNspace,
},
Namespace: payload.Namespace || undefinedNspace,
uid: `["${payload.Namespace || undefinedNspace}","${dc}","${id}"]`,
@ -61,7 +64,10 @@ module('Integration | Serializer | token', function(hooks) {
});
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace || undefinedNspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -2,7 +2,11 @@ import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { get } from 'consul-ui/tests/helpers/api';
import { HEADERS_SYMBOL as META } from 'consul-ui/utils/http/consul';
import {
HEADERS_SYMBOL as META,
HEADERS_DATACENTER as DC,
HEADERS_NAMESPACE as NSPACE,
} from 'consul-ui/utils/http/consul';
module('Integration | Serializer | topology', function(hooks) {
setupTest(hooks);
@ -11,6 +15,7 @@ module('Integration | Serializer | topology', function(hooks) {
const dc = 'dc-1';
const id = 'slug';
const kind = '';
const nspace = 'default';
const request = {
url: `/v1/internal/ui/service-topology/${id}?dc=${dc}&kind=${kind}`,
};
@ -18,11 +23,14 @@ module('Integration | Serializer | topology', function(hooks) {
const expected = {
Datacenter: dc,
[META]: {},
uid: `["default","${dc}","${id}"]`,
uid: `["${nspace}","${dc}","${id}"]`,
};
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const headers = {
[DC]: dc,
[NSPACE]: nspace,
};
const body = payload;
return cb(headers, body);
},

View File

@ -1,5 +1,7 @@
import { moduleFor, test } from 'ember-qunit';
import repo from 'consul-ui/tests/helpers/repo';
import { env } from '../../../../env';
const NAME = 'kv';
moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, {
// Specify the other units that are required for this test.
@ -26,14 +28,17 @@ const undefinedNspace = 'default';
return service.findAllBySlug({ id, dc, ns: nspace || undefinedNspace });
},
function performAssertion(actual, expected) {
const expectedNspace = env('CONSUL_NSPACES_ENABLED')
? nspace || undefinedNspace
: 'default';
assert.deepEqual(
actual,
expected(function(payload) {
return payload.map(item => {
return {
Datacenter: dc,
Namespace: nspace || undefinedNspace,
uid: `["${nspace || undefinedNspace}","${dc}","${item}"]`,
Namespace: expectedNspace,
uid: `["${expectedNspace}","${dc}","${item}"]`,
Key: item,
};
});

View File

@ -62,23 +62,8 @@ const undefinedNspace = 'default';
return service.findBySlug({ id, dc, ns: nspace || undefinedNspace });
},
function performAssertion(actual, expected) {
assert.deepEqual(
actual,
expected(function(payload) {
const item = payload;
return Object.assign({}, item, {
Datacenter: dc,
Namespace: item.Namespace || undefinedNspace,
uid: `["${item.Namespace || undefinedNspace}","${dc}","${item.ID}"]`,
meta: {
cacheControl: undefined,
cursor: undefined,
dc: dc,
nspace: item.Namespace || undefinedNspace,
},
});
})
);
assert.equal(actual.uid, `["${nspace || undefinedNspace}","${dc}","${actual.ID}"]`);
assert.equal(actual.Datacenter, dc);
}
);
});

View File

@ -60,25 +60,11 @@ const undefinedNspace = 'default';
return service.findBySlug({ id, dc, ns: nspace || undefinedNspace });
},
function performAssertion(actual, expected) {
assert.deepEqual(
actual,
expected(function(payload) {
const item = payload;
return Object.assign({}, item, {
Datacenter: dc,
CreateTime: new Date(item.CreateTime),
Namespace: item.Namespace || undefinedNspace,
uid: `["${item.Namespace || undefinedNspace}","${dc}","${item.AccessorID}"]`,
meta: {
cacheControl: undefined,
cursor: undefined,
dc: dc,
nspace: item.Namespace || undefinedNspace,
},
Policies: createPolicies(item),
});
})
);
expected(function(item) {
assert.equal(actual.uid, `["${nspace || undefinedNspace}","${dc}","${item.AccessorID}"]`);
assert.equal(actual.Datacenter, dc);
assert.deepEqual(actual.Policies, createPolicies(item));
});
}
);
});

View File

@ -1,11 +1,7 @@
import { module } from 'qunit';
import test from 'ember-sinon-qunit/test-support/test';
import { setupTest } from 'ember-qunit';
import {
HEADERS_SYMBOL as META,
HEADERS_DATACENTER as DC,
HEADERS_NAMESPACE as NSPACE,
} from 'consul-ui/utils/http/consul';
import { HEADERS_SYMBOL as META } from 'consul-ui/utils/http/consul';
module('Unit | Serializer | application', function(hooks) {
setupTest(hooks);
@ -65,10 +61,7 @@ module('Unit | Serializer | application', function(hooks) {
const expected = {
Datacenter: 'dc-1',
Name: 'name',
[META]: {
[DC.toLowerCase()]: 'dc-1',
[NSPACE.toLowerCase()]: '',
},
[META]: {},
'primary-key-name': 'name',
};
const respond = function(cb) {

View File

@ -42,7 +42,9 @@ module('Unit | Serializer | kv', function(hooks) {
['respondForCreateRecord', 'respondForUpdateRecord'].forEach(function(item) {
const actual = serializer[item](
function(cb) {
const headers = {};
const headers = {
'X-Consul-Namespace': 'default',
};
const body = true;
return cb(headers, body);
},
@ -71,7 +73,9 @@ module('Unit | Serializer | kv', function(hooks) {
['respondForCreateRecord', 'respondForUpdateRecord'].forEach(function(item) {
const actual = serializer[item](
function(cb) {
const headers = {};
const headers = {
'X-Consul-Namespace': 'default',
};
const body = {
Key: uid,
Datacenter: dc,

View File

@ -14,7 +14,7 @@ module('Unit | Utility | create fingerprinter', function() {
uid: '["namespace","dc","slug"]',
};
const fingerprint = createFingerprinter('Datacenter', 'Namespace');
const actual = fingerprint('uid', 'ID', 'dc')(obj);
const actual = fingerprint('uid', 'ID', 'dc', 'namespace')(obj);
assert.deepEqual(actual, expected);
});
test("fingerprint returns a 'unique' fingerprinted object based on primary, slug and foreign keys, and uses default namespace if none set", function(assert) {
@ -28,7 +28,7 @@ module('Unit | Utility | create fingerprinter', function() {
uid: '["default","dc","slug"]',
};
const fingerprint = createFingerprinter('Datacenter', 'Namespace');
const actual = fingerprint('uid', 'ID', 'dc')(obj);
const actual = fingerprint('uid', 'ID', 'dc', 'default')(obj);
assert.deepEqual(actual, expected);
});
test("fingerprint throws an error if it can't find a foreignKey", function(assert) {