From bae5bc16b03af30facbb1371632be24a98169db0 Mon Sep 17 00:00:00 2001 From: Phil Renaud Date: Wed, 27 Apr 2022 12:11:24 -0400 Subject: [PATCH] [ui, mirage] Evaluation mocks (#12471) * Linear and Branching mock evaluations * De-comment * test-trigger * Making evaluation trees dynamic * Reinstated job relationship on eval mock * Dasherize job prefix back to normal * Handle bug where UUIDKey is not present on job * Appending node to eval * Job ID as a passed property * Remove unused import * Branching evals set up as generatable --- ui/app/utils/properties/short-uuid.js | 2 +- ui/mirage/config.js | 17 +- ui/mirage/factories/evaluation.js | 52 ++++-- ui/mirage/factories/job.js | 2 +- ui/mirage/models/evaluation-stub.js | 3 + ui/mirage/models/evaluation.js | 5 + ui/mirage/scenarios/default.js | 86 ++++++++-- ui/mirage/serializers/evaluation.js | 6 + ui/mirage/utils.js | 222 +------------------------- 9 files changed, 136 insertions(+), 259 deletions(-) create mode 100644 ui/mirage/models/evaluation-stub.js create mode 100644 ui/mirage/models/evaluation.js create mode 100644 ui/mirage/serializers/evaluation.js diff --git a/ui/app/utils/properties/short-uuid.js b/ui/app/utils/properties/short-uuid.js index 4c7862f4c..167769f72 100644 --- a/ui/app/utils/properties/short-uuid.js +++ b/ui/app/utils/properties/short-uuid.js @@ -7,6 +7,6 @@ import { computed } from '@ember/object'; // short: shortUUIDProperty('id') // 123456 export default function shortUUIDProperty(uuidKey) { return computed(uuidKey, function () { - return this.get(uuidKey).split('-')[0]; + return this.get(uuidKey)?.split('-')[0]; }); } diff --git a/ui/mirage/config.js b/ui/mirage/config.js index 7582e228f..f048b8311 100644 --- a/ui/mirage/config.js +++ b/ui/mirage/config.js @@ -6,7 +6,6 @@ import { generateDiff } from './factories/job-version'; import { generateTaskGroupFailures } from './factories/evaluation'; import { copy } from 'ember-copy'; import formatHost from 'nomad-ui/utils/format-host'; -import { generateAcceptanceTestEvalMock } from './utils'; export function findLeader(schema) { const agent = schema.agents.first(); @@ -263,19 +262,9 @@ export default function () { }); this.get('/evaluations'); - this.get( - '/evaluation/:id', - function ({ evaluations }, { params, queryParams }) { - const showRelated = queryParams.related; - - if (showRelated) { - // we are dealing with a "related" request - return the mock - return generateAcceptanceTestEvalMock(params.id); - } - - return evaluations.find(params.id); - } - ); + this.get('/evaluation/:id', function ({ evaluations }, { params }) { + return evaluations.find(params.id); + }); this.get('/deployment/allocations/:id', function (schema, { params }) { const job = schema.jobs.find(schema.deployments.find(params.id).jobId); diff --git a/ui/mirage/factories/evaluation.js b/ui/mirage/factories/evaluation.js index 4986675a1..1ea767717 100644 --- a/ui/mirage/factories/evaluation.js +++ b/ui/mirage/factories/evaluation.js @@ -31,9 +31,17 @@ const generateCountMap = (keysCount, list) => () => { }; const generateNodesAvailable = generateCountMap(5, DATACENTERS); -const generateClassFiltered = generateCountMap(3, provide(10, faker.hacker.abbreviation)); +const generateClassFiltered = generateCountMap( + 3, + provide(10, faker.hacker.abbreviation) +); const generateClassExhausted = generateClassFiltered; -const generateDimensionExhausted = generateCountMap(1, ['cpu', 'mem', 'disk', 'iops']); +const generateDimensionExhausted = generateCountMap(1, [ + 'cpu', + 'mem', + 'disk', + 'iops', +]); const generateQuotaExhausted = generateDimensionExhausted; const generateScores = generateCountMap(1, ['binpack', 'job-anti-affinity']); const generateConstraintFiltered = generateCountMap(2, [ @@ -59,7 +67,9 @@ export default Factory.extend({ createIndex: () => faker.random.number({ min: 10, max: 2000 }), createTime() { - return faker.date.past(2 / 365, new Date(this.modifyTime / 1000000)) * 1000000; + return ( + faker.date.past(2 / 365, new Date(this.modifyTime / 1000000)) * 1000000 + ); }, waitUntil: null, @@ -68,14 +78,22 @@ export default Factory.extend({ status: 'blocked', afterCreate(evaluation, server) { assignJob(evaluation, server); - const taskGroups = server.db.taskGroups.where({ jobId: evaluation.jobId }); + const taskGroups = server.db.taskGroups.where({ + jobId: evaluation.jobId, + }); const taskGroupNames = taskGroups.mapBy('name'); - const failedTaskGroupsCount = faker.random.number({ min: 1, max: taskGroupNames.length }); + const failedTaskGroupsCount = faker.random.number({ + min: 1, + max: taskGroupNames.length, + }); const failedTaskGroupNames = []; for (let i = 0; i < failedTaskGroupsCount; i++) { failedTaskGroupNames.push( - ...taskGroupNames.splice(faker.random.number(taskGroupNames.length - 1), 1) + ...taskGroupNames.splice( + faker.random.number(taskGroupNames.length - 1), + 1 + ) ); } @@ -103,7 +121,9 @@ function assignJob(evaluation, server) { server.db.jobs.length ); - const job = evaluation.jobId ? server.db.jobs.find(evaluation.jobId) : pickOne(server.db.jobs); + const job = evaluation.jobId + ? server.db.jobs.find(evaluation.jobId) + : pickOne(server.db.jobs); evaluation.update({ jobId: job.id, }); @@ -115,12 +135,18 @@ export function generateTaskGroupFailures() { NodesEvaluated: faker.random.number({ min: 1, max: 100 }), NodesExhausted: faker.random.number({ min: 1, max: 100 }), - NodesAvailable: faker.random.number(10) >= 7 ? generateNodesAvailable() : null, - ClassFiltered: faker.random.number(10) >= 7 ? generateClassFiltered() : null, - ConstraintFiltered: faker.random.number(10) >= 7 ? generateConstraintFiltered() : null, - ClassExhausted: faker.random.number(10) >= 7 ? generateClassExhausted() : null, - DimensionExhausted: faker.random.number(10) >= 7 ? generateDimensionExhausted() : null, - QuotaExhausted: faker.random.number(10) >= 7 ? generateQuotaExhausted() : null, + NodesAvailable: + faker.random.number(10) >= 7 ? generateNodesAvailable() : null, + ClassFiltered: + faker.random.number(10) >= 7 ? generateClassFiltered() : null, + ConstraintFiltered: + faker.random.number(10) >= 7 ? generateConstraintFiltered() : null, + ClassExhausted: + faker.random.number(10) >= 7 ? generateClassExhausted() : null, + DimensionExhausted: + faker.random.number(10) >= 7 ? generateDimensionExhausted() : null, + QuotaExhausted: + faker.random.number(10) >= 7 ? generateQuotaExhausted() : null, Scores: faker.random.number(10) >= 7 ? generateScores() : null, }; } diff --git a/ui/mirage/factories/job.js b/ui/mirage/factories/job.js index 9d34e14d3..d937924a5 100644 --- a/ui/mirage/factories/job.js +++ b/ui/mirage/factories/job.js @@ -288,7 +288,7 @@ export default Factory.extend({ if (!job.shallow) { const knownEvaluationProperties = { - job, + jobId: job.id, namespace: job.namespace, }; server.createList( diff --git a/ui/mirage/models/evaluation-stub.js b/ui/mirage/models/evaluation-stub.js new file mode 100644 index 000000000..770b50936 --- /dev/null +++ b/ui/mirage/models/evaluation-stub.js @@ -0,0 +1,3 @@ +import { Model } from 'ember-cli-mirage'; + +export default Model.extend({}); diff --git a/ui/mirage/models/evaluation.js b/ui/mirage/models/evaluation.js new file mode 100644 index 000000000..c72142388 --- /dev/null +++ b/ui/mirage/models/evaluation.js @@ -0,0 +1,5 @@ +import { Model, hasMany, belongsTo } from 'ember-cli-mirage'; + +export default Model.extend({ + relatedEvals: hasMany('evaluation-stub'), +}); diff --git a/ui/mirage/scenarios/default.js b/ui/mirage/scenarios/default.js index 139b4d4c3..b7a98a98a 100644 --- a/ui/mirage/scenarios/default.js +++ b/ui/mirage/scenarios/default.js @@ -20,9 +20,11 @@ const allScenarios = { ...sysbatchScenarios, }; -const scenario = getScenarioQueryParameter() || getConfigValue('mirageScenario', 'emptyCluster'); +const scenario = + getScenarioQueryParameter() || + getConfigValue('mirageScenario', 'emptyCluster'); -export default function(server) { +export default function (server) { const activeScenario = allScenarios[scenario]; if (!activeScenario) { throw new Error( @@ -44,14 +46,74 @@ function smallCluster(server) { server.create('feature', { name: 'Dynamic Application Sizing' }); server.createList('agent', 3, 'withConsulLink', 'withVaultLink'); server.createList('node', 5); - server.createList('job', 5, { createRecommendations: true }); + server.createList('job', 1, { createRecommendations: true }); server.createList('allocFile', 5); server.create('allocFile', 'dir', { depth: 2 }); server.createList('csi-plugin', 2); + // #region evaluations + + // Branching: a single eval that relates to N-1 mutually-unrelated evals + const NUM_BRANCHING_EVALUATIONS = 3; + Array(NUM_BRANCHING_EVALUATIONS) + .fill() + .map((_, i) => { + return { + evaluation: server.create('evaluation', { + id: `branching_${i}`, + previousEval: i > 0 ? `branching_0` : '', + jobID: pickOne(server.db.jobs).id, + }), + + evaluationStub: server.create('evaluation-stub', { + id: `branching_${i}`, + previousEval: i > 0 ? `branching_0` : '', + status: 'failed', + }), + }; + }) + .map((x, i, all) => { + x.evaluation.update({ + relatedEvals: + i === 0 + ? all.filter((_, j) => j !== 0).map((e) => e.evaluation) + : all.filter((_, j) => j !== i).map((e) => e.evaluation), + }); + return x; + }); + + // Linear: a long line of N related evaluations + const NUM_LINEAR_EVALUATIONS = 20; + Array(NUM_LINEAR_EVALUATIONS) + .fill() + .map((_, i) => { + return { + evaluation: server.create('evaluation', { + id: `linear_${i}`, + previousEval: i > 0 ? `linear_${i - 1}` : '', + jobID: pickOne(server.db.jobs).id, + }), + + evaluationStub: server.create('evaluation-stub', { + id: `linear_${i}`, + previousEval: i > 0 ? `linear_${i - 1}` : '', + nextEval: `linear_${i + 1}`, + status: 'failed', + }), + }; + }) + .map((x, i, all) => { + x.evaluation.update({ + relatedEvals: all.filter((_, j) => i !== j).map((e) => e.evaluation), + }); + return x; + }); + + // #endregion evaluations + const csiAllocations = server.createList('allocation', 5); const volumes = server.schema.csiVolumes.all().models; - csiAllocations.forEach(alloc => { + csiAllocations.forEach((alloc) => { const volume = pickOne(volumes); volume.writeAllocs.add(alloc); volume.readAllocs.add(alloc); @@ -120,7 +182,11 @@ function everyFeature(server) { namespaceId: 'default', createAllocations: false, }); - server.create('job', { type: 'batch', failedPlacements: true, namespaceId: 'default' }); + server.create('job', { + type: 'batch', + failedPlacements: true, + namespaceId: 'default', + }); server.create('job', { type: 'system', namespaceId: 'default' }); server.create('job', 'periodic', { namespaceId: 'default' }); server.create('job', 'parameterized', { namespaceId: 'default' }); @@ -147,15 +213,17 @@ function createNamespaces(server) { } function createRegions(server) { - ['americas', 'europe', 'asia', 'some-long-name-just-to-test'].forEach(id => { - server.create('region', { id }); - }); + ['americas', 'europe', 'asia', 'some-long-name-just-to-test'].forEach( + (id) => { + server.create('region', { id }); + } + ); } /* eslint-disable */ function logTokens(server) { console.log('TOKENS:'); - server.db.tokens.forEach(token => { + server.db.tokens.forEach((token) => { console.log(` Name: ${token.name} Secret: ${token.secretId} diff --git a/ui/mirage/serializers/evaluation.js b/ui/mirage/serializers/evaluation.js new file mode 100644 index 000000000..3febce3ed --- /dev/null +++ b/ui/mirage/serializers/evaluation.js @@ -0,0 +1,6 @@ +import ApplicationSerializer from './application'; + +export default ApplicationSerializer.extend({ + embed: true, + include: ['relatedEvals'], +}); diff --git a/ui/mirage/utils.js b/ui/mirage/utils.js index 554696850..9bf29ad82 100644 --- a/ui/mirage/utils.js +++ b/ui/mirage/utils.js @@ -26,6 +26,7 @@ export function arrToObj(prop, alias = '') { } export const generateAcceptanceTestEvalMock = (id) => { + return { CreateIndex: 20, CreateTime: 1647899150314738000, @@ -267,224 +268,3 @@ export const generateAcceptanceTestEvalMock = (id) => { Wait: 20000000000, }; }; - -export const MOCK_EVALUATION = { - CreateIndex: 20, - CreateTime: 1647899150314738000, - ID: 'fede162c-26a6-c108-178b-1c140f9f5680', - JobID: 'example', - JobModifyIndex: 10, - ModifyIndex: 31, - ModifyTime: 1647899318007569000, - Namespace: 'default', - NextEval: 'fd1cd898-d655-c7e4-17f6-a1a2e98b18ef', - PreviousEval: 'd8a5c14f-120a-3d83-6305-90927356dd6c', - Priority: 50, - RelatedEvals: [ - { - BlockedEval: '', - CreateIndex: 31, - CreateTime: 1647899318007563000, - DeploymentID: '', - ID: 'fd1cd898-d655-c7e4-17f6-a1a2e98b18ef', - JobID: 'example', - ModifyIndex: 44, - ModifyTime: 1647899591412413000, - Namespace: 'default', - NextEval: 'cac7dfa0-b79b-ee55-c86a-0ca89dffb9e1', - NodeID: '', - PreviousEval: 'fede162c-26a6-c108-178b-1c140f9f5680', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 10, - CreateTime: 1647899129298997000, - DeploymentID: '', - ID: 'd8a5c14f-120a-3d83-6305-90927356dd6c', - JobID: 'example', - ModifyIndex: 20, - ModifyTime: 1647899150314745000, - Namespace: 'default', - NextEval: 'fede162c-26a6-c108-178b-1c140f9f5680', - NodeID: '', - PreviousEval: '', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'job-register', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 44, - CreateTime: 1647899591412410000, - DeploymentID: '', - ID: 'cac7dfa0-b79b-ee55-c86a-0ca89dffb9e1', - JobID: 'example', - ModifyIndex: 53, - ModifyTime: 1647899729480596000, - Namespace: 'default', - NextEval: 'e49bf53c-da6a-c869-8317-f2089682f503', - NodeID: '', - PreviousEval: 'fd1cd898-d655-c7e4-17f6-a1a2e98b18ef', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 53, - CreateTime: 1647899729480592000, - DeploymentID: '', - ID: 'e49bf53c-da6a-c869-8317-f2089682f503', - JobID: 'example', - ModifyIndex: 64, - ModifyTime: 1647899881302731000, - Namespace: 'default', - NextEval: 'a8d29cfc-517c-2e4c-9722-b47e84152c64', - NodeID: '', - PreviousEval: 'cac7dfa0-b79b-ee55-c86a-0ca89dffb9e1', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 64, - CreateTime: 1647899881302723000, - DeploymentID: '', - ID: 'a8d29cfc-517c-2e4c-9722-b47e84152c64', - JobID: 'example', - ModifyIndex: 81, - ModifyTime: 1647900212725381000, - Namespace: 'default', - NextEval: 'b37d06e4-4eb4-b29d-3b4a-b0c7bf2528ad', - NodeID: '', - PreviousEval: 'e49bf53c-da6a-c869-8317-f2089682f503', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 81, - CreateTime: 1647900212725376000, - DeploymentID: '', - ID: 'b37d06e4-4eb4-b29d-3b4a-b0c7bf2528ad', - JobID: 'example', - ModifyIndex: 97, - ModifyTime: 1647900516944239000, - Namespace: 'default', - NextEval: 'd7c50aa5-5bf1-5119-d7e7-0d0ae5381856', - NodeID: '', - PreviousEval: 'a8d29cfc-517c-2e4c-9722-b47e84152c64', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 97, - CreateTime: 1647900516944236000, - DeploymentID: '', - ID: 'd7c50aa5-5bf1-5119-d7e7-0d0ae5381856', - JobID: 'example', - ModifyIndex: 114, - ModifyTime: 1647900825385587000, - Namespace: 'default', - NextEval: 'ea2239aa-26d6-8874-8c56-e1600585772b', - NodeID: '', - PreviousEval: 'b37d06e4-4eb4-b29d-3b4a-b0c7bf2528ad', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 114, - CreateTime: 1647900825385584000, - DeploymentID: '', - ID: 'ea2239aa-26d6-8874-8c56-e1600585772b', - JobID: 'example', - ModifyIndex: 128, - ModifyTime: 1647900979511304000, - Namespace: 'default', - NextEval: '25a2dd19-8d22-d1dd-280a-79860c9b8bdb', - NodeID: '', - PreviousEval: 'd7c50aa5-5bf1-5119-d7e7-0d0ae5381856', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 128, - CreateTime: 1647900979511301000, - DeploymentID: '', - ID: '25a2dd19-8d22-d1dd-280a-79860c9b8bdb', - JobID: 'example', - ModifyIndex: 136, - ModifyTime: 1647901211369652000, - Namespace: 'default', - NextEval: '1fded690-20ad-6afa-3b89-59e319dfce18', - NodeID: '', - PreviousEval: 'ea2239aa-26d6-8874-8c56-e1600585772b', - Priority: 50, - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - { - BlockedEval: '', - CreateIndex: 136, - CreateTime: 1647901211369648000, - DeploymentID: '', - ID: '1fded690-20ad-6afa-3b89-59e319dfce18', - JobID: 'example', - ModifyIndex: 136, - ModifyTime: 1647901211369648000, - Namespace: 'default', - NextEval: '', - NodeID: '', - PreviousEval: '25a2dd19-8d22-d1dd-280a-79860c9b8bdb', - Priority: 50, - Status: 'pending', - StatusDescription: '', - TriggeredBy: 'failed-follow-up', - Type: 'service', - WaitUntil: null, - }, - ], - Status: 'failed', - StatusDescription: 'evaluation reached delivery limit (3)', - TriggeredBy: 'failed-follow-up', - Type: 'service', - Wait: 20000000000, -};