Merge pull request #4994 from hashicorp/b-ui-dots-in-tasks

UI: Bugs around dots in task/task-group/driver names
This commit is contained in:
Michael Lange 2018-12-17 15:50:31 -08:00 committed by GitHub
commit e1e5aa21ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 703 additions and 15 deletions

View file

@ -13,8 +13,9 @@ export default ApplicationSerializer.extend({
normalize(typeHash, hash) { normalize(typeHash, hash) {
// Transform the map-based TaskStates object into an array-based // Transform the map-based TaskStates object into an array-based
// TaskState fragment list // TaskState fragment list
hash.TaskStates = Object.keys(get(hash, 'TaskStates') || {}).map(key => { const states = hash.TaskStates || {};
const state = get(hash, `TaskStates.${key}`); hash.TaskStates = Object.keys(states).map(key => {
const state = states[key] || {};
const summary = { Name: key }; const summary = { Name: key };
Object.keys(state).forEach(stateKey => (summary[stateKey] = state[stateKey])); Object.keys(state).forEach(stateKey => (summary[stateKey] = state[stateKey]));
summary.Resources = hash.TaskResources && hash.TaskResources[key]; summary.Resources = hash.TaskResources && hash.TaskResources[key];

View file

@ -9,8 +9,9 @@ export default ApplicationSerializer.extend({
normalize(typeHash, hash) { normalize(typeHash, hash) {
if (hash) { if (hash) {
hash.TaskGroupSummaries = Object.keys(get(hash, 'TaskGroups') || {}).map(key => { const taskGroups = hash.TaskGroups || {};
const deploymentStats = get(hash, `TaskGroups.${key}`); hash.TaskGroupSummaries = Object.keys(taskGroups).map(key => {
const deploymentStats = taskGroups[key];
return assign({ Name: key }, deploymentStats); return assign({ Name: key }, deploymentStats);
}); });

View file

@ -7,8 +7,10 @@ export default ApplicationSerializer.extend({
system: service(), system: service(),
normalize(typeHash, hash) { normalize(typeHash, hash) {
hash.FailedTGAllocs = Object.keys(hash.FailedTGAllocs || {}).map(key => { const failures = hash.FailedTGAllocs || {};
return assign({ Name: key }, get(hash, `FailedTGAllocs.${key}`) || {}); hash.FailedTGAllocs = Object.keys(failures).map(key => {
const propertiesForKey = failures[key] || {};
return assign({ Name: key }, propertiesForKey);
}); });
hash.PlainJobId = hash.JobID; hash.PlainJobId = hash.JobID;

View file

@ -1,11 +1,11 @@
import { get } from '@ember/object';
import { assign } from '@ember/polyfills'; import { assign } from '@ember/polyfills';
import ApplicationSerializer from './application'; import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({ export default ApplicationSerializer.extend({
normalize(typeHash, hash) { normalize(typeHash, hash) {
hash.FailedTGAllocs = Object.keys(hash.FailedTGAllocs || {}).map(key => { const failures = hash.FailedTGAllocs || {};
return assign({ Name: key }, get(hash, `FailedTGAllocs.${key}`) || {}); hash.FailedTGAllocs = Object.keys(failures).map(key => {
return assign({ Name: key }, failures[key] || {});
}); });
return this._super(...arguments); return this._super(...arguments);
}, },

View file

@ -9,8 +9,9 @@ export default ApplicationSerializer.extend({
hash.ID = JSON.stringify([hash.JobID, hash.Namespace || 'default']); hash.ID = JSON.stringify([hash.JobID, hash.Namespace || 'default']);
hash.JobID = hash.ID; hash.JobID = hash.ID;
hash.TaskGroupSummaries = Object.keys(get(hash, 'Summary') || {}).map(key => { const fullSummary = hash.Summary || {};
const allocStats = get(hash, `Summary.${key}`) || {}; hash.TaskGroupSummaries = Object.keys(fullSummary).map(key => {
const allocStats = fullSummary[key] || {};
const summary = { Name: key }; const summary = { Name: key };
Object.keys(allocStats).forEach( Object.keys(allocStats).forEach(

View file

@ -1,4 +1,3 @@
import { get } from '@ember/object';
import { assign } from '@ember/polyfills'; import { assign } from '@ember/polyfills';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import ApplicationSerializer from './application'; import ApplicationSerializer from './application';
@ -13,8 +12,9 @@ export default ApplicationSerializer.extend({
normalize(modelClass, hash) { normalize(modelClass, hash) {
// Transform the map-based Drivers object into an array-based NodeDriver fragment list // Transform the map-based Drivers object into an array-based NodeDriver fragment list
hash.Drivers = Object.keys(get(hash, 'Drivers') || {}).map(key => { const drivers = hash.Drivers || {};
return assign({}, get(hash, `Drivers.${key}`), { Name: key }); hash.Drivers = Object.keys(drivers).map(key => {
return assign({}, drivers[key], { Name: key });
}); });
return this._super(modelClass, hash); return this._super(modelClass, hash);

View file

@ -0,0 +1,149 @@
import { test } from 'ember-qunit';
import AllocationModel from 'nomad-ui/models/allocation';
import moduleForSerializer from '../../helpers/module-for-serializer';
moduleForSerializer('allocation', 'Unit | Serializer | Allocation', {
needs: [
'service:token',
'service:system',
'serializer:allocation',
'transform:fragment',
'transform:fragment-array',
'model:job',
'model:node',
'model:namespace',
'model:evaluation',
'model:allocation',
'model:resources',
'model:task-state',
'model:reschedule-event',
],
});
const sampleDate = new Date('2018-12-12T00:00:00');
const normalizationTestCases = [
{
name: 'Normal',
in: {
ID: 'test-allocation',
JobID: 'test-summary',
Name: 'test-summary[1]',
Namespace: 'test-namespace',
TaskGroup: 'test-group',
CreateTime: +sampleDate * 1000000,
ModifyTime: +sampleDate * 1000000,
TaskStates: {
testTask: {
State: 'running',
Failed: false,
},
},
},
out: {
data: {
id: 'test-allocation',
type: 'allocation',
attributes: {
taskGroupName: 'test-group',
name: 'test-summary[1]',
modifyTime: sampleDate,
createTime: sampleDate,
states: [
{
name: 'testTask',
state: 'running',
failed: false,
},
],
},
relationships: {
followUpEvaluation: {
data: null,
},
nextAllocation: {
data: null,
},
previousAllocation: {
data: null,
},
job: {
data: {
id: '["test-summary","test-namespace"]',
type: 'job',
},
},
},
},
},
},
{
name: 'Dots in task names',
in: {
ID: 'test-allocation',
JobID: 'test-summary',
Name: 'test-summary[1]',
Namespace: 'test-namespace',
TaskGroup: 'test-group',
CreateTime: +sampleDate * 1000000,
ModifyTime: +sampleDate * 1000000,
TaskStates: {
'one.two': {
State: 'running',
Failed: false,
},
'three.four': {
State: 'pending',
Failed: true,
},
},
},
out: {
data: {
id: 'test-allocation',
type: 'allocation',
attributes: {
taskGroupName: 'test-group',
name: 'test-summary[1]',
modifyTime: sampleDate,
createTime: sampleDate,
states: [
{
name: 'one.two',
state: 'running',
failed: false,
},
{
name: 'three.four',
state: 'pending',
failed: true,
},
],
},
relationships: {
followUpEvaluation: {
data: null,
},
nextAllocation: {
data: null,
},
previousAllocation: {
data: null,
},
job: {
data: {
id: '["test-summary","test-namespace"]',
type: 'job',
},
},
},
},
},
},
];
normalizationTestCases.forEach(testCase => {
test(`normalization: ${testCase.name}`, function(assert) {
assert.deepEqual(this.subject().normalize(AllocationModel, testCase.in), testCase.out);
});
});

View file

@ -0,0 +1,129 @@
import { test } from 'ember-qunit';
import DeploymentModel from 'nomad-ui/models/deployment';
import moduleForSerializer from '../../helpers/module-for-serializer';
moduleForSerializer('deployment', 'Unit | Serializer | Deployment', {
needs: [
'adapter:application',
'serializer:deployment',
'service:system',
'service:token',
'transform:fragment-array',
'model:allocation',
'model:job',
'model:task-group-deployment-summary',
],
});
const normalizationTestCases = [
{
name: 'Normal',
in: {
ID: 'test-deployment',
JobID: 'test-job',
Namespace: 'test-namespace',
Status: 'canceled',
TaskGroups: {
taskGroup: {
DesiredCanaries: 2,
},
},
},
out: {
data: {
id: 'test-deployment',
type: 'deployment',
attributes: {
status: 'canceled',
taskGroupSummaries: [
{
name: 'taskGroup',
desiredCanaries: 2,
},
],
},
relationships: {
allocations: {
links: {
related: '/v1/deployment/allocations/test-deployment',
},
},
job: {
data: {
id: '["test-job","test-namespace"]',
type: 'job',
},
},
jobForLatest: {
data: {
id: '["test-job","test-namespace"]',
type: 'job',
},
},
},
},
},
},
{
name: 'Dots in task group names',
in: {
ID: 'test-deployment',
JobID: 'test-job',
Namespace: 'test-namespace',
Status: 'canceled',
TaskGroups: {
'one.two': {
DesiredCanaries: 2,
},
'three.four': {
DesiredCanaries: 3,
},
},
},
out: {
data: {
id: 'test-deployment',
type: 'deployment',
attributes: {
status: 'canceled',
taskGroupSummaries: [
{
name: 'one.two',
desiredCanaries: 2,
},
{
name: 'three.four',
desiredCanaries: 3,
},
],
},
relationships: {
allocations: {
links: {
related: '/v1/deployment/allocations/test-deployment',
},
},
job: {
data: {
id: '["test-job","test-namespace"]',
type: 'job',
},
},
jobForLatest: {
data: {
id: '["test-job","test-namespace"]',
type: 'job',
},
},
},
},
},
},
];
normalizationTestCases.forEach(testCase => {
test(`normalization: ${testCase.name}`, function(assert) {
assert.deepEqual(this.subject().normalize(DeploymentModel, testCase.in), testCase.out);
});
});

View file

@ -0,0 +1,104 @@
import { test } from 'ember-qunit';
import EvaluationModel from 'nomad-ui/models/evaluation';
import moduleForSerializer from '../../helpers/module-for-serializer';
moduleForSerializer('evaluation', 'Unit | Serializer | Evaluation', {
needs: [
'serializer:evaluation',
'service:system',
'transform:fragment-array',
'model:job',
'model:placement-failure',
],
});
const normalizationTestCases = [
{
name: 'Normal',
in: {
ID: 'test-eval',
FailedTGAllocs: {
taskGroup: {
NodesAvailable: 10,
},
},
JobID: 'some-job-id',
Job: {
Namespace: 'test-namespace',
},
},
out: {
data: {
id: 'test-eval',
type: 'evaluation',
attributes: {
failedTGAllocs: [
{
name: 'taskGroup',
nodesAvailable: 10,
},
],
},
relationships: {
job: {
data: {
id: '["some-job-id","test-namespace"]',
type: 'job',
},
},
},
},
},
},
{
name: 'Dots in task group names',
in: {
ID: 'test-eval',
FailedTGAllocs: {
'one.two': {
NodesAvailable: 10,
},
'three.four': {
NodesAvailable: 25,
},
},
JobID: 'some-job-id',
Job: {
Namespace: 'test-namespace',
},
},
out: {
data: {
id: 'test-eval',
type: 'evaluation',
attributes: {
failedTGAllocs: [
{
name: 'one.two',
nodesAvailable: 10,
},
{
name: 'three.four',
nodesAvailable: 25,
},
],
},
relationships: {
job: {
data: {
id: '["some-job-id","test-namespace"]',
type: 'job',
},
},
},
},
},
},
];
normalizationTestCases.forEach(testCase => {
test(`normalization: ${testCase.name}`, function(assert) {
assert.deepEqual(this.subject().normalize(EvaluationModel, testCase.in), testCase.out);
});
});

View file

@ -0,0 +1,94 @@
import { test } from 'ember-qunit';
import JobPlanModel from 'nomad-ui/models/job-plan';
import moduleForSerializer from '../../helpers/module-for-serializer';
moduleForSerializer('job-plan', 'Unit | Serializer | JobPlan', {
needs: [
'service:token',
'service:system',
'serializer:job-plan',
'transform:fragment-array',
'model:placement-failure',
],
});
const normalizationTestCases = [
{
name: 'Normal',
in: {
ID: 'test-plan',
Diff: {
Arbitrary: 'Value',
},
FailedTGAllocs: {
taskGroup: {
NodesAvailable: 10,
},
},
},
out: {
data: {
id: 'test-plan',
type: 'job-plan',
attributes: {
diff: {
Arbitrary: 'Value',
},
failedTGAllocs: [
{
name: 'taskGroup',
nodesAvailable: 10,
},
],
},
relationships: {},
},
},
},
{
name: 'Dots in task names',
in: {
ID: 'test-plan',
Diff: {
Arbitrary: 'Value',
},
FailedTGAllocs: {
'one.two': {
NodesAvailable: 10,
},
'three.four': {
NodesAvailable: 25,
},
},
},
out: {
data: {
id: 'test-plan',
type: 'job-plan',
attributes: {
diff: {
Arbitrary: 'Value',
},
failedTGAllocs: [
{
name: 'one.two',
nodesAvailable: 10,
},
{
name: 'three.four',
nodesAvailable: 25,
},
],
},
relationships: {},
},
},
},
];
normalizationTestCases.forEach(testCase => {
test(`normalization: ${testCase.name}`, function(assert) {
assert.deepEqual(this.subject().normalize(JobPlanModel, testCase.in), testCase.out);
});
});

View file

@ -0,0 +1,103 @@
import { test } from 'ember-qunit';
import JobSummaryModel from 'nomad-ui/models/job-summary';
import moduleForSerializer from '../../helpers/module-for-serializer';
moduleForSerializer('job-summary', 'Unit | Serializer | JobSummary', {
needs: [
'serializer:job-summary',
'transform:fragment-array',
'model:job',
'model:task-group-summary',
],
});
const normalizationTestCases = [
{
name: 'Normal',
in: {
JobID: 'test-summary',
Namespace: 'test-namespace',
Summary: {
taskGroup: {
Complete: 0,
Running: 1,
},
},
},
out: {
data: {
id: '["test-summary","test-namespace"]',
type: 'job-summary',
attributes: {
taskGroupSummaries: [
{
name: 'taskGroup',
completeAllocs: 0,
runningAllocs: 1,
},
],
},
relationships: {
job: {
data: {
id: '["test-summary","test-namespace"]',
type: 'job',
},
},
},
},
},
},
{
name: 'Dots in task group names',
in: {
JobID: 'test-summary',
Namespace: 'test-namespace',
Summary: {
'one.two': {
Complete: 0,
Running: 1,
},
'three.four': {
Failed: 2,
Lost: 3,
},
},
},
out: {
data: {
id: '["test-summary","test-namespace"]',
type: 'job-summary',
attributes: {
taskGroupSummaries: [
{
name: 'one.two',
completeAllocs: 0,
runningAllocs: 1,
},
{
name: 'three.four',
failedAllocs: 2,
lostAllocs: 3,
},
],
},
relationships: {
job: {
data: {
id: '["test-summary","test-namespace"]',
type: 'job',
},
},
},
},
},
},
];
normalizationTestCases.forEach(testCase => {
test(`normalization: ${testCase.name}`, function(assert) {
assert.deepEqual(this.subject().normalize(JobSummaryModel, testCase.in), testCase.out);
});
});

View file

@ -7,11 +7,20 @@ import pushPayloadToStore from '../../utils/push-payload-to-store';
moduleForSerializer('node', 'Unit | Serializer | Node', { moduleForSerializer('node', 'Unit | Serializer | Node', {
needs: [ needs: [
'serializer:node', 'adapter:application',
'service:config', 'service:config',
'serializer:node',
'service:system',
'service:token',
'transform:fragment', 'transform:fragment',
'transform:fragment-array', 'transform:fragment-array',
'model:node-attributes',
'model:resources',
'model:drain-strategy',
'model:node-driver',
'model:node-event',
'model:allocation', 'model:allocation',
'model:job',
], ],
}); });
@ -75,3 +84,98 @@ test('local store is culled to reflect the state of findAll requests', function(
function makeNode(id, name, ip) { function makeNode(id, name, ip) {
return { ID: id, Name: name, HTTPAddr: ip }; return { ID: id, Name: name, HTTPAddr: ip };
} }
const normalizationTestCases = [
{
name: 'Normal',
in: {
ID: 'test-node',
HTTPAddr: '867.53.0.9:4646',
Drain: false,
Drivers: {
docker: {
Detected: true,
Healthy: false,
},
},
},
out: {
data: {
id: 'test-node',
type: 'node',
attributes: {
isDraining: false,
httpAddr: '867.53.0.9:4646',
drivers: [
{
name: 'docker',
detected: true,
healthy: false,
},
],
},
relationships: {
allocations: {
links: {
related: '/v1/node/test-node/allocations',
},
},
},
},
},
},
{
name: 'Dots in driver names',
in: {
ID: 'test-node',
HTTPAddr: '867.53.0.9:4646',
Drain: false,
Drivers: {
'my.driver': {
Detected: true,
Healthy: false,
},
'my.other.driver': {
Detected: false,
Healthy: false,
},
},
},
out: {
data: {
id: 'test-node',
type: 'node',
attributes: {
isDraining: false,
httpAddr: '867.53.0.9:4646',
drivers: [
{
name: 'my.driver',
detected: true,
healthy: false,
},
{
name: 'my.other.driver',
detected: false,
healthy: false,
},
],
},
relationships: {
allocations: {
links: {
related: '/v1/node/test-node/allocations',
},
},
},
},
},
},
];
normalizationTestCases.forEach(testCase => {
test(`normalization: ${testCase.name}`, function(assert) {
assert.deepEqual(this.subject().normalize(NodeModel, testCase.in), testCase.out);
});
});