Merge pull request #118 from hashicorp/feature-host-set-api

Feature host set api
This commit is contained in:
Susmitha Girumala authored and GitHub committed 2020-08-17 10:05:43 -04:00
commit 9845a60ea9
16 files changed
+231 -16

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
import ApplicationAdapter from './application';
import { inject as service } from '@ember/service';
export default class HostSetAdapter extends ApplicationAdapter {
// =services
@service store;
// =methods
/**
* Append a host catalog URL ahead of the host sets path if `hostCatalogID` is
* passed via adapter options. Otherwise, generate the prefix as normal.
*
* TODO: generalize the interface to resource-prefixed URLs by accepting
* a modelName and an ID, rather than looking for a known key.
*
* @override
* @param {string} path
* @param {string} parentURL
* @param {string} modelName
* @param {string} id
* @param {object} snapshot
* @return {string} urlPrefix
*/
urlPrefix(path, parentURL, modelName, id, snapshot) {
const hostCatalogID = snapshot?.adapterOptions?.hostCatalogID;
if (hostCatalogID) {
const hostCatalogAdapter = this.store.adapterFor('host-catalog');
return hostCatalogAdapter
._buildPrefixedURL('host-catalog', hostCatalogID, snapshot);
} else {
return super.urlPrefix(...arguments);
}
}
}
@@ -0,0 +1,42 @@
import BaseModel from '../../models/base';
import { attr } from '@ember-data/model';
/**
* HostSet is a collection of Hosts created and managed by a HostCatalog
*/
export default class GeneratedHostSetModel extends BaseModel {
// =attributes
@attr('string', {
description: 'The type of the resource, to help differentiate schemas'
}) type;
@attr('string', {
description: 'Optional name for identification purposes'
}) name;
@attr('string', {
description: 'Optional user-set description for identification purposes'
}) description;
@attr('date', {
description: 'The time this resource was created\nOutput only.',
readOnly: true
}) created_time;
@attr('date', {
description: 'The time this resource was last updated\nOutput only.',
readOnly: true
}) updated_time;
@attr('number', {
description: 'Current version number of this resource.',
})
version;
@attr('number', {
description: 'The total count of hosts in this host set\nOutput only.'
}) size;
}
+26 -12
View File
@@ -46,6 +46,31 @@ export default Mixin.create({
return '';
},
/**
* Builds the (mostly full) URL with a prefix, but not the suffix.
* The `_buildURL` method adds a suffix.
* Do not call directly.
* @override
* @param {String} modelName
* @param {String} id
* @return {String} url
*/
_buildPrefixedURL(modelName, id, snapshot) {
let path;
let url = [];
const host = get(this, 'host');
const prefix = this.urlPrefix(null, null, modelName, id, snapshot);
if (modelName) {
path = this.pathForType(modelName);
if (path) url.push(path);
}
if (id) url.push(encodeURIComponent(id));
if (prefix) url.unshift(prefix);
url = url.join('/');
if (!host && url && url.charAt(0) !== '/') url = '/' + url;
return `${url}`;
},
/**
* Overrides the default `_buildURL` with a nearly identical version.
* This method simply passes arguments into the `urlPrefix` method for
@@ -58,19 +83,8 @@ export default Mixin.create({
* @return {String} url
*/
_buildURL(modelName, id, snapshot) {
let path;
let url = [];
const host = get(this, 'host');
const prefix = this.urlPrefix(null, null, modelName, id, snapshot);
const url = this._buildPrefixedURL(modelName, id, snapshot);
const suffix = this.urlSuffix(modelName, id, snapshot);
if (modelName) {
path = this.pathForType(modelName);
if (path) url.push(path);
}
if (id) url.push(encodeURIComponent(id));
if (prefix) url.unshift(prefix);
url = url.join('/');
if (!host && url && url.charAt(0) !== '/') url = '/' + url;
return `${url}${suffix}`;
},
+9 -1
View File
@@ -1,3 +1,11 @@
import GeneratedHostCatalogModel from '../generated/models/host-catalog';
import { hasMany } from '@ember-data/model';
export default class HostCatalogModel extends GeneratedHostCatalogModel { }
export default class HostCatalogModel extends GeneratedHostCatalogModel {
/**
* @type {HostSetModel[]}
*/
@hasMany('host-set') hostSets;
}
+13
View File
@@ -0,0 +1,13 @@
import GeneratedHostSetModel from '../generated/models/host-set';
import { belongsTo } from '@ember-data/model';
export default class HostSetModel extends GeneratedHostSetModel {
// =relationships
/**
* @type {HostCatalogModel}
*/
@belongsTo('host-catalog') hostCatalog;
}
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/adapters/host-set';
+1
View File
@@ -0,0 +1 @@
export { default } from 'api/models/host-set';
@@ -0,0 +1,28 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Adapter | host set', function(hooks) {
setupTest(hooks);
test('it generates correct complete URLs', function (assert) {
assert.expect(2);
const scopeID = 'o_1';
const hostCatalogID = 'hc_098';
const method = 'my-custom-method';
const mockSnapshot = {
adapterOptions: {
scopeID,
method
}
};
const adapter = this.owner.lookup('adapter:host-set');
// Without hostCatalogID...
let url = adapter.buildURL('host-set', null, mockSnapshot, 'findAll');
assert.equal(url, '/v1/scopes/o_1/host-sets:my-custom-method');
// With hostCatalogID...
mockSnapshot.adapterOptions.hostCatalogID = hostCatalogID;
url = adapter.buildURL('host-set', null, mockSnapshot, 'findAll');
assert.equal(url, '/v1/scopes/o_1/host-catalogs/hc_098/host-sets:my-custom-method');
});
});
@@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | host set', 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('host-set', {});
assert.ok(model);
});
});
@@ -1,4 +1,20 @@
import Route from '@ember/routing/route';
export default class ScopesScopeProjectsProjectHostCatalogsHostCatalogRoute extends Route {
// =methods
/**
* Load a host catalog.
* @param {object} params
* @param {string} params.host_catalog_id
* @return {HostCatalogModel}
*/
async model({ host_catalog_id }) {
const { id: scopeID } = this.modelFor('scopes.scope');
return this.store.findRecord('host-catalog', host_catalog_id, {
adapterOptions: { scopeID },
});
}
}
+8
View File
@@ -88,6 +88,14 @@ export default function() {
this.patch('/scopes/:scope_id/host-catalogs/:id');
this.del('/scopes/:scope_id/host-catalogs/:id');
// host-set
this.get('/scopes/:scope_id/host-catalogs/:host_catalog_id/host-sets');
this.post('/scopes/:scope_id/host-catalogs/:host_catalog_id/host-sets');
this.get('/scopes/:scope_id/host-catalogs/:host_catalog_id/host-sets/:id');
this.patch('/scopes/:scope_id/host-catalogs/:host_catalog_id/host-sets/:id');
this.del('/scopes/:scope_id/host-catalogs/:host_catalog_id/host-sets/:id');
// Uncomment the following line and the Response import above
// Then change the response code to simulate error responses.
// this.get('/scopes/:scope_id/projects', () => new Response(505));
+14 -1
View File
@@ -1,3 +1,16 @@
import factory from '../generated/factories/host-catalog';
import { trait } from 'ember-cli-mirage';
export default factory.extend();
export default factory.extend({
/**
* Create catalogs with associated host sets and hosts.
*/
withChildren: trait({
afterCreate(record, server) {
const host_set_ids = server.createList('host-set', 3).map(set => set.id);
record.update({ host_set_ids });
}
})
});
+3
View File
@@ -0,0 +1,3 @@
import factory from '../generated/factories/host-set';
export default factory.extend();
+1 -1
View File
@@ -14,7 +14,7 @@ export default factory.extend({
}, 'withChildren');
}
if (record.type === 'org') {
server.createList('scope', 5, {
server.createList('scope', 3, {
type: 'project',
scope: { id: record.id, type: record.type }
});
@@ -0,0 +1,17 @@
import { Factory } from 'ember-cli-mirage';
import { random, date } from 'faker';
/**
* GeneratedHostSetModelFactory
*/
export default Factory.extend({
type: 'static',
name: () => random.words(),
description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
version: () => random.number(),
size: () => random.number(),
});
+1 -1
View File
@@ -27,7 +27,7 @@ export default function(server) {
server.db.scopes.where({type: 'project'}).forEach(projectScope => {
const scope = { id: projectScope.id, type: projectScope.type };
server.createList('host-catalog', 2, { scope });
server.createList('host-catalog', 2, { scope }, 'withChildren');
});
}