ui: Adds ember-data blueprints for Consul specific HTTP adapter etc (#6461)

* ui: Adds ember-data blueprints for Consul specific HTTP adapter etc

These are currently quite Consul specific, but we also overwrite the
default model-test blueprint to keep the names consistent (dasherized)
for easy test filtering.

```
ember generate [adapter|serializer|model|repository|route] <name>
```
This commit is contained in:
John Cowen 2019-11-19 10:35:10 +00:00 committed by John Cowen
parent 4c24e8b072
commit 39010d2b76
22 changed files with 591 additions and 0 deletions

View File

@ -0,0 +1,27 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const useTestFrameworkDetector = require('@ember-data/-build-infra/src/utilities/test-framework-detector');
const path = require('path');
module.exports = useTestFrameworkDetector({
description: 'Generates a Consul HTTP ember-data adapter unit and integration tests',
root: __dirname,
fileMapTokens(options) {
return {
__root__() {
return 'tests';
},
__path__() {
return '';
}
};
},
locals(options) {
return {
};
},
});

View File

@ -0,0 +1,36 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Integration | Adapter | <%= dasherizedModuleName %>', function(hooks) {
setupTest(hooks);
const dc = 'dc-1';
const id = 'slug';
test('requestForQuery returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>');
const client = this.owner.lookup('service:client/http');
const expected = `GET /v1/<%= dasherizedModuleName %>?dc=${dc}`;
const actual = adapter.requestForQuery(client.url, {
dc: dc,
});
assert.equal(actual, expected);
});
test('requestForQueryRecord returns the correct url/method', function(assert) {
const adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>');
const client = this.owner.lookup('service:client/http');
const expected = `GET /v1/<%= dasherizedModuleName %>/${id}?dc=${dc}`;
const actual = adapter.requestForQueryRecord(client.url, {
dc: dc,
id: id,
});
assert.equal(actual, expected);
});
test("requestForQueryRecord throws if you don't specify an id", function(assert) {
const adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>');
const client = this.owner.lookup('service:client/http');
assert.throws(function() {
adapter.requestForQueryRecord(client.url, {
dc: dc,
});
});
});
});

View File

@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Adapter | <%= dasherizedModuleName %>', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>');
assert.ok(adapter);
});
});

View File

@ -0,0 +1,21 @@
import Adapter from './application';
export default Adapter.extend({
requestForQuery: function(request, { dc, index }) {
return request`
GET /v1/<%= dasherizedModuleName %>?${{ dc }}
${{ index }}
`;
},
requestForQueryRecord: function(request, { dc, index, id }) {
if (typeof id === 'undefined') {
throw new Error('You must specify an id');
}
return request`
GET /v1/<%= dasherizedModuleName %>/${id}?${{ dc }}
${{ index }}
`;
},
});

View File

@ -0,0 +1,37 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const path = require('path');
const isModuleUnificationProject = require('@ember-data/-build-infra/src/utilities/module-unification').isModuleUnificationProject;
module.exports = {
description: 'Generates a Consul HTTP ember-data adapter',
availableOptions: [{ name: 'base-class', type: String }],
root: __dirname,
fileMapTokens(options) {
if (isModuleUnificationProject(this.project)) {
return {
__root__() {
return 'src';
},
__path__(options) {
return path.join('data', 'models', options.dasherizedModuleName);
},
__name__() {
return 'adapter';
},
};
}
},
locals(options) {
// Return custom template variables here.
return {
};
}
// afterInstall(options) {
// // Perform extra work here.
// }
};

View File

@ -0,0 +1,27 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const useTestFrameworkDetector = require('@ember-data/-build-infra/src/utilities/test-framework-detector');
const path = require('path');
module.exports = useTestFrameworkDetector({
description: 'Generates a Consul ember-data model unit tests',
root: __dirname,
fileMapTokens(options) {
return {
__root__() {
return 'tests';
},
__path__() {
return '';
}
};
},
locals(options) {
return {
};
},
});

View File

@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | <%= dasherizedModuleName %>', 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('<%= dasherizedModuleName %>', {});
assert.ok(model);
});
});

View File

@ -0,0 +1,10 @@
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export const PRIMARY_KEY = 'uid';
export const SLUG_KEY = 'ID';
export default Model.extend({
[PRIMARY_KEY]: attr('string'),
[SLUG_KEY]: attr('string'),
Datacenter: attr('string'),
});

View File

@ -0,0 +1,37 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const path = require('path');
const isModuleUnificationProject = require('@ember-data/-build-infra/src/utilities/module-unification').isModuleUnificationProject;
module.exports = {
description: 'Generates a Consul HTTP ember-data model',
availableOptions: [],
root: __dirname,
fileMapTokens(options) {
if (isModuleUnificationProject(this.project)) {
return {
__root__() {
return 'src';
},
__path__(options) {
return path.join('data', 'models', options.dasherizedModuleName);
},
__name__() {
return 'model';
},
};
}
},
locals(options) {
// Return custom template variables here.
return {
};
}
// afterInstall(options) {
// // Perform extra work here.
// }
};

View File

@ -0,0 +1,28 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const useTestFrameworkDetector = require('@ember-data/-build-infra/src/utilities/test-framework-detector');
const path = require('path');
module.exports = useTestFrameworkDetector({
description: 'Generates a Consul HTTP ember-data serializer unit and integration tests',
root: __dirname,
fileMapTokens(options) {
return {
__root__() {
return 'tests';
},
__path__() {
return '';
}
};
},
locals(options) {
return {
screamingSnakeCaseModuleName: options.entity.name.replace('-', '_').toUpperCase()
};
},
});

View File

@ -0,0 +1,75 @@
import { moduleFor, test } from 'ember-qunit';
import repo from 'consul-ui/tests/helpers/repo';
moduleFor('service:repository/<%= dasherizedModuleName %>', 'Integration | Repository | <%= dasherizedModuleName %>', {
// Specify the other units that are required for this test.
integration: true,
});
const dc = 'dc-1';
const id = 'slug';
const now = new Date().getTime();
test('findByDatacenter returns the correct data for list endpoint', function(assert) {
get(this.subject(), 'store').serializerFor('<%= dasherizedModuleName %>').timestamp = function() {
return now;
};
return repo(
'Service',
'findAllByDatacenter',
this.subject(),
function retrieveStub(stub) {
return stub(`/v1/<%= dasherizedModuleName %>?dc=${dc}`, {
CONSUL_<%= screamingSnakeCaseModuleName %>_COUNT: '100',
});
},
function performTest(service) {
return service.findAllByDatacenter(dc);
},
function performAssertion(actual, expected) {
assert.deepEqual(
actual,
expected(function(payload) {
return payload.map(item =>
Object.assign({}, item, {
SyncTime: now,
Datacenter: dc,
uid: `["${dc}","${item.Name}"]`,
})
);
})
);
}
);
});
test('findBySlug returns the correct data for item endpoint', function(assert) {
return repo(
'Service',
'findBySlug',
this.subject(),
function retrieveStub(stub) {
return stub(`/v1/<%= dasherizedModuleName %>/${id}?dc=${dc}`, {
CONSUL_<%= screamingSnakeCaseModuleName %>_COUNT: 1,
});
},
function performTest(service) {
return service.findBySlug(id, dc);
},
function performAssertion(actual, expected) {
assert.deepEqual(
actual,
expected(function(payload) {
return Object.assign(
{},
{
Datacenter: dc,
uid: `["${dc}","${id}"]`,
meta: {
cursor: undefined
}
},
payload
);
})
);
}
);
});

View File

@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Repository | <%= dasherizedModuleName %>', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let repo = this.owner.lookup('service:repository/<%= dasherizedModuleName %>');
assert.ok(repo);
});
});

View File

@ -0,0 +1,8 @@
import RepositoryService from 'consul-ui/services/repository';
const modelName = '<%= dasherizedModuleName %>';
export default RepositoryService.extend({
getModelName: function() {
return modelName;
},
});

View File

@ -0,0 +1,27 @@
'use strict';
const path = require('path');
module.exports = {
description: 'Generates a Consul repository',
availableOptions: [],
root: __dirname,
fileMapTokens(options) {
return {
__path__() {
return path.join('services', 'repository');
}
};
},
locals(options) {
// Return custom template variables here.
return {
};
}
// afterInstall(options) {
// // Perform extra work here.
// }
};

View File

@ -0,0 +1,4 @@
import Route from '@ember/routing/route';
export default Route.extend({
});

View File

@ -0,0 +1 @@
{{outlet}}

View File

@ -0,0 +1,43 @@
/* eslint-env node */
const chalk = require('chalk');
module.exports = Object.assign(
require('ember-source/blueprints/route/index.js'),
{
afterInstall: function(options) {
updateRouter.call(this, 'add', options);
},
afterUninstall: function(options) {
updateRouter.call(this, 'remove', options);
}
}
);
function updateRouter(action, options) {
var entity = options.entity;
var actionColorMap = {
add: 'green',
remove: 'red'
};
var color = actionColorMap[action] || 'gray';
if (this.shouldTouchRouter(entity.name, options)) {
this.ui.writeLine(`we don't currently update the router for you, please edit ${findRouter(options).join('/')}`);
this._writeStatusToUI(chalk[color], action + ' route', entity.name);
}
}
function findRouter(options) {
var routerPathParts = [options.project.root];
if (options.dummy && options.project.isEmberCLIAddon()) {
routerPathParts = routerPathParts.concat(['tests', 'dummy', 'app', 'router.js']);
} else {
routerPathParts = routerPathParts.concat(['app', 'router.js']);
}
return routerPathParts;
}

View File

@ -0,0 +1,27 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const useTestFrameworkDetector = require('@ember-data/-build-infra/src/utilities/test-framework-detector');
const path = require('path');
module.exports = useTestFrameworkDetector({
description: 'Generates a Consul HTTP ember-data serializer unit and integration tests',
root: __dirname,
fileMapTokens(options) {
return {
__root__() {
return 'tests';
},
__path__() {
return '';
}
};
},
locals(options) {
return {
};
},
});

View File

@ -0,0 +1,62 @@
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';
module('Integration | Serializer | <%= dasherizedModuleName %>', function(hooks) {
setupTest(hooks);
test('respondForQuery returns the correct data for list endpoint', function(assert) {
const serializer = this.owner.lookup('serializer:<%= dasherizedModuleName %>');
const dc = 'dc-1';
const request = {
url: `/v1/<%= dasherizedModuleName %>?dc=${dc}`,
};
return get(request.url).then(function(payload) {
const expected = payload.map(item =>
Object.assign({}, item, {
Datacenter: dc,
uid: `["${dc}","${item.Name}"]`,
})
);
const actual = serializer.respondForQuery(
function(cb) {
const headers = {};
const body = payload;
return cb(headers, body);
},
{
dc: dc,
}
);
assert.deepEqual(actual, expected);
});
});
test('respondForQueryRecord returns the correct data for item endpoint', function(assert) {
const serializer = this.owner.lookup('serializer:<%= dasherizedModuleName %>');
const dc = 'dc-1';
const id = 'slug';
const request = {
url: `/v1/<%= dasherizedModuleName %>/${id}?dc=${dc}`,
};
return get(request.url).then(function(payload) {
const expected = {
Datacenter: dc,
[META]: {},
uid: `["${dc}","${id}"]`,
};
const actual = serializer.respondForQueryRecord(
function(cb) {
const headers = {};
const body = payload;
return cb(headers, body);
},
{
dc: dc,
id: id,
}
);
assert.deepEqual(actual, expected);
});
});
});

View File

@ -0,0 +1,23 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Serializer | <%= dasherizedModuleName %>', 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('<%= dasherizedModuleName %>');
assert.ok(serializer);
});
test('it serializes records', function(assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('<%= dasherizedModuleName %>', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
});

View File

@ -0,0 +1,24 @@
import Serializer from './application';
import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/<%= dasherizedModuleName %>';
export default Serializer.extend({
primaryKey: PRIMARY_KEY,
slugKey: SLUG_KEY,
// respondForQueryRecord: function(respond, query) {
// return this._super(
// function(cb) {
// return respond(
// function(headers, body) {
// return cb(
// headers,
// body
// );
// }
// )
// },
// query
// );
// },
});

View File

@ -0,0 +1,37 @@
/*eslint node/no-extraneous-require: "off"*/
'use strict';
const path = require('path');
const isModuleUnificationProject = require('@ember-data/-build-infra/src/utilities/module-unification').isModuleUnificationProject;
module.exports = {
description: 'Generates a Consul HTTP ember-data serializer',
availableOptions: [{ name: 'base-class', type: String }],
root: __dirname,
fileMapTokens(options) {
if (isModuleUnificationProject(this.project)) {
return {
__root__() {
return 'src';
},
__path__(options) {
return path.join('data', 'models', options.dasherizedModuleName);
},
__name__() {
return 'serializer';
},
};
}
},
locals(options) {
// Return custom template variables here.
return {
};
}
// afterInstall(options) {
// // Perform extra work here.
// }
};