diff --git a/ui-v2/app/adapters/service-instance.js b/ui-v2/app/adapters/service-instance.js new file mode 100644 index 0000000000..b853f71471 --- /dev/null +++ b/ui-v2/app/adapters/service-instance.js @@ -0,0 +1,23 @@ +import Adapter from './application'; +// TODO: Update to use this.formatDatacenter() +export default Adapter.extend({ + requestForQuery: function(request, { dc, ns, index, id, uri }) { + if (typeof id === 'undefined') { + throw new Error('You must specify an id'); + } + return request` + GET /v1/health/service/${id}?${{ dc }} + X-Request-ID: ${uri} + + ${{ + ...this.formatNspace(ns), + index, + }} + `; + }, + requestForQueryRecord: function(request, { dc, ns, index, id, uri }) { + // query and queryRecord both use the same endpoint + // they are just serialized differently + return this.requestForQuery(...arguments); + }, +}); diff --git a/ui-v2/app/components/consul-service-instance-list/index.hbs b/ui-v2/app/components/consul-service-instance-list/index.hbs index bbaae929a1..b6ab32f5c3 100644 --- a/ui-v2/app/components/consul-service-instance-list/index.hbs +++ b/ui-v2/app/components/consul-service-instance-list/index.hbs @@ -20,7 +20,7 @@ {{/if}} -{{#if (get proxies item.Service.ID)}} +{{#if item.ProxyInstance}}
diff --git a/ui-v2/app/controllers/dc/services/show.js b/ui-v2/app/controllers/dc/services/show.js index 04cc4bdf17..4941ddad09 100644 --- a/ui-v2/app/controllers/dc/services/show.js +++ b/ui-v2/app/controllers/dc/services/show.js @@ -1,9 +1,11 @@ import Controller from '@ember/controller'; import { get } from '@ember/object'; +import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; export default Controller.extend({ dom: service('dom'), notify: service('flashMessages'), + item: alias('items.firstObject'), actions: { error: function(e) { if (e.target.readyState === 1) { diff --git a/ui-v2/app/controllers/dc/services/show/instances.js b/ui-v2/app/controllers/dc/services/show/instances.js index 2b1f8a7563..a33e295d30 100644 --- a/ui-v2/app/controllers/dc/services/show/instances.js +++ b/ui-v2/app/controllers/dc/services/show/instances.js @@ -1,9 +1,6 @@ import Controller from '@ember/controller'; -import { computed } from '@ember/object'; -import { alias } from '@ember/object/computed'; export default Controller.extend({ - items: alias('item.Nodes'), queryParams: { sortBy: 'sort', search: { @@ -11,12 +8,4 @@ export default Controller.extend({ replace: true, }, }, - keyedProxies: computed('proxies.[]', function() { - const proxies = {}; - this.proxies.forEach(item => { - proxies[item.ServiceProxy.DestinationServiceID] = true; - }); - - return proxies; - }), }); diff --git a/ui-v2/app/models/service-instance.js b/ui-v2/app/models/service-instance.js new file mode 100644 index 0000000000..4b8946098b --- /dev/null +++ b/ui-v2/app/models/service-instance.js @@ -0,0 +1,31 @@ +import Model from 'ember-data/model'; +import attr from 'ember-data/attr'; +import { belongsTo } from 'ember-data/relationships'; +import { filter, alias } from '@ember/object/computed'; + +export const PRIMARY_KEY = 'uid'; +export const SLUG_KEY = 'Node.Node,Service.ID'; + +export default Model.extend({ + [PRIMARY_KEY]: attr('string'), + [SLUG_KEY]: attr('string'), + Datacenter: attr('string'), + // ProxyInstance is the ember-data model relationship + ProxyInstance: belongsTo('Proxy'), + // Proxy is the actual JSON api response + Proxy: attr(), + Node: attr(), + Service: attr(), + Checks: attr(), + SyncTime: attr('number'), + meta: attr(), + Tags: alias('Service.Tags'), + Meta: alias('Service.Meta'), + Namespace: alias('Service.Namespace'), + ServiceChecks: filter('Checks', function(item, i, arr) { + return item.ServiceID !== ''; + }), + NodeChecks: filter('Checks', function(item, i, arr) { + return item.ServiceID === ''; + }), +}); diff --git a/ui-v2/app/models/service.js b/ui-v2/app/models/service.js index a6a30e1df0..67bf5ea508 100644 --- a/ui-v2/app/models/service.js +++ b/ui-v2/app/models/service.js @@ -14,8 +14,8 @@ export default Model.extend({ }, }), InstanceCount: attr('number'), - ProxyFor: attr(), Proxy: attr(), + ProxyFor: attr(), Kind: attr('string'), ExternalSources: attr(), GatewayConfig: attr(), diff --git a/ui-v2/app/routes/dc/services/instance/addresses.js b/ui-v2/app/routes/dc/services/instance/addresses.js index 671854a549..17be8ca7c2 100644 --- a/ui-v2/app/routes/dc/services/instance/addresses.js +++ b/ui-v2/app/routes/dc/services/instance/addresses.js @@ -10,7 +10,7 @@ export default Route.extend({ return this.modelFor(parent); }, afterModel: function(model, transition) { - if (get(model, 'item.Kind') !== 'mesh-gateway') { + if (get(model, 'item.Service.Kind') !== 'mesh-gateway') { const parent = this.routeName .split('.') .slice(0, -1) diff --git a/ui-v2/app/routes/dc/services/instance/upstreams.js b/ui-v2/app/routes/dc/services/instance/upstreams.js index 93a2a80b96..a31853b18a 100644 --- a/ui-v2/app/routes/dc/services/instance/upstreams.js +++ b/ui-v2/app/routes/dc/services/instance/upstreams.js @@ -10,7 +10,7 @@ export default Route.extend({ return this.modelFor(parent); }, afterModel: function(model, transition) { - if (get(model, 'item.Kind') !== 'connect-proxy') { + if (get(model, 'item.Service.Kind') !== 'connect-proxy') { const parent = this.routeName .split('.') .slice(0, -1) diff --git a/ui-v2/app/routes/dc/services/show.js b/ui-v2/app/routes/dc/services/show.js index 9f6a39de9c..04db68abf8 100644 --- a/ui-v2/app/routes/dc/services/show.js +++ b/ui-v2/app/routes/dc/services/show.js @@ -13,13 +13,15 @@ export default Route.extend({ slug: params.name, dc: dc, nspace: nspace, - item: this.data.source(uri => uri`/${nspace}/${dc}/service/${params.name}`), + items: this.data.source( + uri => uri`/${nspace}/${dc}/service-instances/for-service/${params.name}` + ), urls: this.settings.findBySlug('urls'), proxies: [], }) .then(model => { return ['connect-proxy', 'mesh-gateway', 'ingress-gateway', 'terminating-gateway'].includes( - get(model, 'item.Service.Kind') + get(model, 'items.firstObject.Service.Kind') ) ? model : hash({ @@ -31,7 +33,9 @@ export default Route.extend({ }); }) .then(model => { - return ['ingress-gateway', 'terminating-gateway'].includes(get(model, 'item.Service.Kind')) + return ['ingress-gateway', 'terminating-gateway'].includes( + get(model, 'items.firstObject.Service.Kind') + ) ? hash({ ...model, gatewayServices: this.data.source( diff --git a/ui-v2/app/serializers/service-instance.js b/ui-v2/app/serializers/service-instance.js new file mode 100644 index 0000000000..4e4f12a58c --- /dev/null +++ b/ui-v2/app/serializers/service-instance.js @@ -0,0 +1,45 @@ +import Serializer from './application'; +import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/service-instance'; + +export default Serializer.extend({ + primaryKey: PRIMARY_KEY, + slugKey: SLUG_KEY, + respondForQuery: function(respond, query) { + return this._super(function(cb) { + return respond(function(headers, body) { + if (body.length === 0) { + const e = new Error(); + e.errors = [ + { + status: '404', + title: 'Not found', + }, + ]; + throw e; + } + return cb(headers, body); + }); + }, query); + }, + respondForQueryRecord: function(respond, query) { + return this._super(function(cb) { + return respond(function(headers, body) { + body = body.find(function(item) { + return item.Node.Node === query.node && item.Service.ID === query.serviceId; + }); + if (typeof body === 'undefined') { + const e = new Error(); + e.errors = [ + { + status: '404', + title: 'Not found', + }, + ]; + throw e; + } + body.Namespace = body.Service.Namespace; + return cb(headers, body); + }); + }, query); + }, +}); diff --git a/ui-v2/app/services/data-source/protocols/http.js b/ui-v2/app/services/data-source/protocols/http.js index 4dc7070a98..1c99bfcb1c 100644 --- a/ui-v2/app/services/data-source/protocols/http.js +++ b/ui-v2/app/services/data-source/protocols/http.js @@ -8,7 +8,8 @@ export default Service.extend({ gateways: service('repository/service'), services: service('repository/service'), service: service('repository/service'), - ['service-instance']: service('repository/service'), + ['service-instance']: service('repository/service-instance'), + ['service-instances']: service('repository/service-instance'), proxies: service('repository/proxy'), ['proxy-instance']: service('repository/proxy'), ['discovery-chain']: service('repository/discovery-chain'), @@ -67,6 +68,14 @@ export default Service.extend({ break; } break; + case 'service-instances': + [method, ...slug] = rest; + switch (method) { + case 'for-service': + find = configuration => repo.findByService(slug, dc, nspace, configuration); + break; + } + break; case 'coordinates': [method, ...slug] = rest; switch (method) { @@ -102,12 +111,15 @@ export default Service.extend({ case 'token': find = configuration => repo.self(rest[1], dc); break; - case 'service': case 'discovery-chain': case 'node': find = configuration => repo.findBySlug(rest[0], dc, nspace, configuration); break; case 'service-instance': + // id, node, service + find = configuration => + repo.findBySlug(rest[0], rest[1], rest[2], dc, nspace, configuration); + break; case 'proxy-instance': // id, node, service find = configuration => diff --git a/ui-v2/app/services/repository/proxy.js b/ui-v2/app/services/repository/proxy.js index 8a70e93d00..9e20745dd1 100644 --- a/ui-v2/app/services/repository/proxy.js +++ b/ui-v2/app/services/repository/proxy.js @@ -19,7 +19,20 @@ export default RepositoryService.extend({ query.index = configuration.cursor; query.uri = configuration.uri; } - return this.store.query(this.getModelName(), query); + return this.store.query(this.getModelName(), query).then(items => { + items.forEach(item => { + // swap out the id for the services id + // so we can then assign the proxy to it if it exists + const id = JSON.parse(item.uid); + id.pop(); + id.push(item.ServiceProxy.DestinationServiceID); + const service = this.store.peekRecord('service-instance', JSON.stringify(id)); + if (service) { + set(service, 'ProxyInstance', item); + } + }); + return items; + }); }, findInstanceBySlug: function(id, node, slug, dc, nspace, configuration) { return this.findAllBySlug(slug, dc, nspace, configuration).then(function(items) { diff --git a/ui-v2/app/services/repository/service-instance.js b/ui-v2/app/services/repository/service-instance.js new file mode 100644 index 0000000000..4b283b3bbc --- /dev/null +++ b/ui-v2/app/services/repository/service-instance.js @@ -0,0 +1,33 @@ +import RepositoryService from 'consul-ui/services/repository'; +const modelName = 'service-instance'; +export default RepositoryService.extend({ + getModelName: function() { + return modelName; + }, + findByService: function(slug, dc, nspace, configuration = {}) { + const query = { + dc: dc, + nspace: nspace, + id: slug, + }; + if (typeof configuration.cursor !== 'undefined') { + query.index = configuration.cursor; + query.uri = configuration.uri; + } + return this.store.query(this.getModelName(), query); + }, + findBySlug: function(serviceId, node, service, dc, nspace, configuration = {}) { + const query = { + dc: dc, + ns: nspace, + serviceId: serviceId, + node: node, + id: service, + }; + if (typeof configuration.cursor !== 'undefined') { + query.index = configuration.cursor; + query.uri = configuration.uri; + } + return this.store.queryRecord(this.getModelName(), query); + }, +}); diff --git a/ui-v2/app/services/repository/service.js b/ui-v2/app/services/repository/service.js index 82c6f4f2d7..1a1d9d903f 100644 --- a/ui-v2/app/services/repository/service.js +++ b/ui-v2/app/services/repository/service.js @@ -1,74 +1,9 @@ import RepositoryService from 'consul-ui/services/repository'; -import { get, set } from '@ember/object'; const modelName = 'service'; export default RepositoryService.extend({ getModelName: function() { return modelName; }, - findBySlug: function(slug, dc) { - return this._super(...arguments).then(function(item) { - // TODO: Move this to the Serializer - const nodes = get(item, 'Nodes'); - if (nodes.length === 0) { - // TODO: Add an store.error("404", "message") or similar - // or move all this to serializer - const e = new Error(); - e.errors = [ - { - status: '404', - title: 'Not found', - }, - ]; - throw e; - } - const service = get(nodes, 'firstObject'); - // TODO: Use [...new Set()] instead of uniq - const tags = nodes - .reduce(function(prev, item) { - return prev.concat(get(item, 'Service.Tags') || []); - }, []) - .uniq(); - set(service, 'Tags', tags); - set(service, 'Nodes', nodes); - set(service, 'meta', get(item, 'meta')); - set(service, 'Namespace', get(item, 'Namespace')); - return service; - }); - }, - findInstanceBySlug: function(id, node, slug, dc, nspace, configuration) { - return this.findBySlug(slug, dc, nspace, configuration).then(function(item) { - // TODO: Move this to the Serializer - // Loop through all the service instances and pick out the one - // that has the same service id AND node name - // node names are unique per datacenter - const i = item.Nodes.findIndex(function(item) { - return item.Service.ID === id && item.Node.Node === node; - }); - if (i !== -1) { - const service = item.Nodes[i].Service; - service.Node = item.Nodes[i].Node; - service.ServiceChecks = item.Nodes[i].Checks.filter(function(item) { - return item.ServiceID != ''; - }); - service.NodeChecks = item.Nodes[i].Checks.filter(function(item) { - return item.ServiceID == ''; - }); - set(service, 'meta', get(item, 'meta')); - set(service, 'Namespace', get(item, 'Namespace')); - return service; - } - // TODO: Add an store.error("404", "message") or similar - // or move all this to serializer - const e = new Error(); - e.errors = [ - { - status: '404', - title: 'Unable to find instance', - }, - ]; - throw e; - }); - }, findGatewayBySlug: function(slug, dc, nspace, configuration = {}) { const query = { dc: dc, diff --git a/ui-v2/app/templates/dc/services/instance.hbs b/ui-v2/app/templates/dc/services/instance.hbs index b3d2672cba..d38e093dba 100644 --- a/ui-v2/app/templates/dc/services/instance.hbs +++ b/ui-v2/app/templates/dc/services/instance.hbs @@ -1,4 +1,4 @@ -{{title item.ID}} +{{title item.Service.ID}} @@ -9,12 +9,12 @@
  1. All Services
  2. -
  3. Service ({{item.Service}})
  4. +
  5. Service ({{item.Service.Service}})

- {{ item.ID }} + {{ item.Service.ID }}

@@ -22,7 +22,7 @@
Service Name
-
{{item.Service}}
+
{{item.Service.Service}}
Node Name
@@ -30,7 +30,7 @@
- {{#let (or item.Address item.Node.Address) as |address|}} + {{#let (or item.Service.Address item.Node.Address) as |address|}} {{address}} {{/let}} @@ -40,7 +40,7 @@ (array (hash label="Health Checks" href=(href-to "dc.services.instance.healthchecks") selected=(is-href "dc.services.instance.healthchecks")) (if - (eq item.Kind 'mesh-gateway') + (eq item.Service.Kind 'mesh-gateway') (hash label="Addresses" href=(href-to "dc.services.instance.addresses") selected=(is-href "dc.services.instance.addresses")) "" ) (if proxy diff --git a/ui-v2/app/templates/dc/services/instance/addresses.hbs b/ui-v2/app/templates/dc/services/instance/addresses.hbs index 732be68412..c147bd74a1 100644 --- a/ui-v2/app/templates/dc/services/instance/addresses.hbs +++ b/ui-v2/app/templates/dc/services/instance/addresses.hbs @@ -1,9 +1,9 @@
- {{#if item.TaggedAddresses }} + {{#if item.Service.TaggedAddresses }} Tag diff --git a/ui-v2/app/templates/dc/services/instance/proxy.hbs b/ui-v2/app/templates/dc/services/instance/proxy.hbs index 011d67f816..2680494b0e 100644 --- a/ui-v2/app/templates/dc/services/instance/proxy.hbs +++ b/ui-v2/app/templates/dc/services/instance/proxy.hbs @@ -1,18 +1,18 @@
- {{#if (gt proxy.Proxy.Upstreams.length 0)}} + {{#if (gt proxy.Service.Proxy.Upstreams.length 0)}}

Upstreams

- +
{{/if}} - {{#if (gt proxy.Proxy.Expose.Paths.length 0)}} + {{#if (gt proxy.Service.Proxy.Expose.Paths.length 0)}}

Exposed paths

The following list shows individual HTTP paths exposed through Envoy for external services like Prometheus. Read more about this in our documentation.

- +
{{/if}} {{#if (or (gt proxy.ServiceChecks.length 0) (gt proxy.NodeChecks.length 0))}} diff --git a/ui-v2/app/templates/dc/services/show.hbs b/ui-v2/app/templates/dc/services/show.hbs index 0519602f62..f74e043bf8 100644 --- a/ui-v2/app/templates/dc/services/show.hbs +++ b/ui-v2/app/templates/dc/services/show.hbs @@ -1,9 +1,9 @@ -{{title item.Service.Service}} - + +{{title item.Service.Service}} {{partial 'dc/services/notifications'}} diff --git a/ui-v2/app/templates/dc/services/show/instances.hbs b/ui-v2/app/templates/dc/services/show/instances.hbs index 5c5a4ca79b..b919a1cd82 100644 --- a/ui-v2/app/templates/dc/services/show/instances.hbs +++ b/ui-v2/app/templates/dc/services/show/instances.hbs @@ -9,7 +9,7 @@ {{/if}} - + diff --git a/ui-v2/app/templates/dc/services/show/tags.hbs b/ui-v2/app/templates/dc/services/show/tags.hbs index 7184728017..016fe25b34 100644 --- a/ui-v2/app/templates/dc/services/show/tags.hbs +++ b/ui-v2/app/templates/dc/services/show/tags.hbs @@ -1,8 +1,9 @@
- {{#if (gt item.Tags.length 0) }} - - {{else}} +{{#let (flatten (map-by "Tags" items)) as |tags|}} + {{#if (gt tags.length 0) }} + + {{else}}

@@ -10,6 +11,7 @@

- {{/if}} + {{/if}} +{{/let}}
diff --git a/ui-v2/app/utils/create-fingerprinter.js b/ui-v2/app/utils/create-fingerprinter.js index 69d2da8a00..9b3843257b 100644 --- a/ui-v2/app/utils/create-fingerprinter.js +++ b/ui-v2/app/utils/create-fingerprinter.js @@ -1,3 +1,4 @@ +import { get } from '@ember/object'; export default function(foreignKey, nspaceKey, hash = JSON.stringify) { return function(primaryKey, slugKey, foreignKeyValue) { if (foreignKeyValue == null || foreignKeyValue.length < 1) { @@ -6,12 +7,12 @@ export default function(foreignKey, nspaceKey, hash = JSON.stringify) { return function(item) { const slugKeys = slugKey.split(','); const slugValues = slugKeys.map(function(slugKey) { - if (item[slugKey] == null || item[slugKey].length < 1) { + if (get(item, slugKey) == null || get(item, slugKey).length < 1) { throw new Error('Unable to create fingerprint, missing slug'); } - return item[slugKey]; + return get(item, slugKey); }); - const nspaceValue = item[nspaceKey] || 'default'; + const nspaceValue = get(item, nspaceKey) || 'default'; return { ...item, ...{ diff --git a/ui-v2/tests/integration/adapters/service-instance-test.js b/ui-v2/tests/integration/adapters/service-instance-test.js new file mode 100644 index 0000000000..ab9b0ca44b --- /dev/null +++ b/ui-v2/tests/integration/adapters/service-instance-test.js @@ -0,0 +1,36 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { env } from '../../../env'; +const shouldHaveNspace = function(nspace) { + return typeof nspace !== 'undefined' && env('CONSUL_NSPACES_ENABLED'); +}; +module('Integration | Adapter | service-instance', function(hooks) { + setupTest(hooks); + const dc = 'dc-1'; + const id = 'service-name'; + const undefinedNspace = 'default'; + [undefinedNspace, 'team-1', undefined].forEach(nspace => { + 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 expected = `GET /v1/health/service/${id}?dc=${dc}${ + shouldHaveNspace(nspace) ? `&ns=${nspace}` : `` + }`; + let actual = adapter.requestForQueryRecord(client.requestParams.bind(client), { + dc: dc, + id: id, + ns: nspace, + }); + assert.equal(`${actual.method} ${actual.url}`, expected); + }); + }); + 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'); + assert.throws(function() { + adapter.requestForQueryRecord(client.url, { + dc: dc, + }); + }); + }); +}); diff --git a/ui-v2/tests/integration/serializers/service-instance-test.js b/ui-v2/tests/integration/serializers/service-instance-test.js new file mode 100644 index 0000000000..e53b6ce3f9 --- /dev/null +++ b/ui-v2/tests/integration/serializers/service-instance-test.js @@ -0,0 +1,54 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { get } from 'consul-ui/tests/helpers/api'; +import { + HEADERS_SYMBOL as META, + HEADERS_DATACENTER as DC, + HEADERS_NAMESPACE as NSPACE, +} from 'consul-ui/utils/http/consul'; +module('Integration | Serializer | service-instance', function(hooks) { + setupTest(hooks); + const dc = 'dc-1'; + const undefinedNspace = 'default'; + [undefinedNspace, 'team-1', undefined].forEach(nspace => { + test(`respondForQueryRecord returns the correct data for item endpoint when nspace is ${nspace}`, function(assert) { + const serializer = this.owner.lookup('serializer:service-instance'); + const id = 'service-name'; + const node = 'node-0'; + const request = { + url: `/v1/health/service/${id}?dc=${dc}${ + typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` + }`, + }; + return get(request.url).then(function(payload) { + payload[0].Node.Node = node; + payload[0].Service.ID = id; + const expected = { + ...payload[0], + Datacenter: dc, + [META]: { + [DC.toLowerCase()]: dc, + [NSPACE.toLowerCase()]: payload[0].Service.Namespace || 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 body = payload; + return cb(headers, body); + }, + { + dc: dc, + ns: nspace, + id: id, + node: node, + serviceId: id, + } + ); + assert.deepEqual(actual, expected); + }); + }); + }); +}); diff --git a/ui-v2/tests/integration/serializers/service-test.js b/ui-v2/tests/integration/serializers/service-test.js index 636f644714..c46dbb6754 100644 --- a/ui-v2/tests/integration/serializers/service-test.js +++ b/ui-v2/tests/integration/serializers/service-test.js @@ -1,11 +1,6 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import { get } from 'consul-ui/tests/helpers/api'; -import { - HEADERS_SYMBOL as META, - 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'; @@ -73,40 +68,5 @@ module('Integration | Serializer | service', function(hooks) { assert.deepEqual(actual, expected); }); }); - test(`respondForQueryRecord returns the correct data for item endpoint when nspace is ${nspace}`, function(assert) { - const serializer = this.owner.lookup('serializer:service'); - const id = 'service-name'; - const request = { - url: `/v1/health/service/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` - }`, - }; - return get(request.url).then(function(payload) { - const expected = { - Datacenter: dc, - [META]: { - [DC.toLowerCase()]: dc, - [NSPACE.toLowerCase()]: payload[0].Service.Namespace || undefinedNspace, - }, - Namespace: payload[0].Service.Namespace || undefinedNspace, - uid: `["${payload[0].Service.Namespace || undefinedNspace}","${dc}","${id}"]`, - Name: id, - Nodes: payload, - }; - const actual = serializer.respondForQueryRecord( - function(cb) { - const headers = {}; - const body = payload; - return cb(headers, body); - }, - { - dc: dc, - ns: nspace, - id: id, - } - ); - assert.deepEqual(actual, expected); - }); - }); }); }); diff --git a/ui-v2/tests/integration/services/repository/service-test.js b/ui-v2/tests/integration/services/repository/service-test.js index a3c87edbea..677d05eec6 100644 --- a/ui-v2/tests/integration/services/repository/service-test.js +++ b/ui-v2/tests/integration/services/repository/service-test.js @@ -7,89 +7,9 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { integration: true, }); const dc = 'dc-1'; -const id = 'token-name'; const now = new Date().getTime(); const undefinedNspace = 'default'; [undefinedNspace, 'team-1', undefined].forEach(nspace => { - test(`findInstanceBySlug calls findBySlug with the correct arguments when nspace is ${nspace}`, function(assert) { - assert.expect(4); - const id = 'id'; - const slug = 'slug'; - const node = 'node-name'; - - const datacenter = 'dc-1'; - const conf = { - cursor: 1, - }; - const service = this.subject(); - service.findBySlug = function(slug, dc, nspace, configuration) { - assert.equal( - arguments.length, - 4, - 'Expected to be called with the correct number of arguments' - ); - assert.equal(dc, datacenter); - assert.deepEqual(configuration, conf); - return Promise.resolve({ Nodes: [] }); - }; - // This will throw an error as we don't resolve any services that match what was requested - // so a 404 is the correct error response - return service.findInstanceBySlug(id, slug, node, datacenter, nspace, conf).catch(function(e) { - assert.equal(e.errors[0].status, '404'); - }); - }); - - test(`findBySlug returns the correct data for item endpoint when the nspace is ${nspace}`, function(assert) { - return repo( - 'Service', - 'findBySlug', - this.subject(), - function(stub) { - return stub( - `/v1/health/service/${id}?dc=${dc}${ - typeof nspace !== 'undefined' ? `&ns=${nspace}` : `` - }`, - { - CONSUL_NODE_COUNT: 1, - } - ); - }, - function(service) { - return service.findBySlug(id, dc, nspace || undefinedNspace); - }, - function(actual, expected) { - assert.deepEqual( - actual, - expected(function(payload) { - // TODO: So this tree is all 'wrong', it's not having any major impact - // this this tree needs revisting to something that makes more sense - payload = Object.assign( - {}, - { Nodes: payload }, - { - Datacenter: dc, - Namespace: payload[0].Service.Namespace || undefinedNspace, - uid: `["${payload[0].Service.Namespace || undefinedNspace}","${dc}","${id}"]`, - } - ); - const nodes = payload.Nodes; - const service = payload.Nodes[0]; - service.Nodes = nodes; - service.Tags = [...new Set(payload.Nodes[0].Service.Tags)]; - service.Namespace = payload.Namespace; - service.meta = { - cacheControl: undefined, - cursor: undefined, - dc: dc, - nspace: payload.Namespace, - }; - - return service; - }) - ); - } - ); - }); test(`findGatewayBySlug returns the correct data for list endpoint when nspace is ${nspace}`, function(assert) { get(this.subject(), 'store').serializerFor(NAME).timestamp = function() { return now; diff --git a/ui-v2/tests/unit/adapters/service-instance-test.js b/ui-v2/tests/unit/adapters/service-instance-test.js new file mode 100644 index 0000000000..d2f3eff5c8 --- /dev/null +++ b/ui-v2/tests/unit/adapters/service-instance-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Adapter | service-instance', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:service-instance'); + assert.ok(adapter); + }); +}); diff --git a/ui-v2/tests/unit/models/service-instance-test.js b/ui-v2/tests/unit/models/service-instance-test.js new file mode 100644 index 0000000000..b18d0ee706 --- /dev/null +++ b/ui-v2/tests/unit/models/service-instance-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Model | service-instance', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('service-instance', {}); + assert.ok(model); + }); +}); diff --git a/ui-v2/tests/unit/serializers/service-instance-test.js b/ui-v2/tests/unit/serializers/service-instance-test.js new file mode 100644 index 0000000000..9402e194f3 --- /dev/null +++ b/ui-v2/tests/unit/serializers/service-instance-test.js @@ -0,0 +1,23 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Serializer | service-instance', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('service-instance'); + + assert.ok(serializer); + }); + + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('service-instance', {}); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); +}); diff --git a/ui-v2/tests/unit/services/repository/service-instance-test.js b/ui-v2/tests/unit/services/repository/service-instance-test.js new file mode 100644 index 0000000000..5ddd6789cd --- /dev/null +++ b/ui-v2/tests/unit/services/repository/service-instance-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Repository | service-instance', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + const repo = this.owner.lookup('service:repository/service-instance'); + assert.ok(repo); + }); +});