From 94df7bc46aaa354519aeb8bc6535087ec2ed2105 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Fri, 4 May 2018 19:04:36 -0700 Subject: [PATCH] Integration tests for the various reschedule events timeline permutations --- ui/app/components/allocation-row.js | 3 +- .../components/reschedule-event-row.hbs | 15 +- .../components/reschedule-event-timeline.hbs | 5 +- ui/mirage/factories/allocation.js | 6 +- .../reschedule-event-timeline-test.js | 198 ++++++++++++++++++ 5 files changed, 213 insertions(+), 14 deletions(-) create mode 100644 ui/tests/integration/reschedule-event-timeline-test.js diff --git a/ui/app/components/allocation-row.js b/ui/app/components/allocation-row.js index dab830468..5a0e92f39 100644 --- a/ui/app/components/allocation-row.js +++ b/ui/app/components/allocation-row.js @@ -24,8 +24,7 @@ export default Component.extend({ stats: null, statsError: false, - // enablePolling: computed(() => !Ember.testing), - enablePolling: false, + enablePolling: computed(() => !Ember.testing), onClick() {}, diff --git a/ui/app/templates/components/reschedule-event-row.hbs b/ui/app/templates/components/reschedule-event-row.hbs index a494ee3cd..733358b3d 100644 --- a/ui/app/templates/components/reschedule-event-row.hbs +++ b/ui/app/templates/components/reschedule-event-row.hbs @@ -1,17 +1,20 @@
  • + {{#if label}} + {{label}} + {{/if}} {{moment-format time "MMMM D, YYYY HH:mm:ss"}}
  • -
  • +
  • {{#unless linkToAllocation}} -
    +
    This Allocation
    {{/unless}}
    - + {{allocation.clientStatus}}
    @@ -21,16 +24,16 @@ Allocation {{#if linkToAllocation}} {{#link-to "allocations.allocation" allocation.id}} - {{allocation.shortId}} + {{allocation.shortId}} {{/link-to}} {{else}} - {{allocation.shortId}} + {{allocation.shortId}} {{/if}} Client - {{#link-to "clients.client" allocation.node.id}} + {{#link-to "clients.client" data-test-node-link allocation.node.id}} {{allocation.node.id}} {{/link-to}} diff --git a/ui/app/templates/components/reschedule-event-timeline.hbs b/ui/app/templates/components/reschedule-event-timeline.hbs index 8a75433c2..1f2f5385c 100644 --- a/ui/app/templates/components/reschedule-event-timeline.hbs +++ b/ui/app/templates/components/reschedule-event-timeline.hbs @@ -6,18 +6,17 @@ time=allocation.nextAllocation.modifyTime}} {{/if}} {{#if allocation.hasStoppedRescheduling}} -
  • +
  • {{x-icon "warning" class="is-warning is-text"}} Nomad has stopped attempting to reschedule this allocation.
  • {{/if}} {{#if (and allocation.followUpEvaluation.waitUntil (not allocation.nextAllocation))}} -
  • +
  • {{x-icon "clock" class="is-info is-text"}} Nomad will attempt to reschedule {{moment-from-now allocation.followUpEvaluation.waitUntil interval=1000}}
  • {{/if}} {{reschedule-event-row - label="This Allocation" allocation=allocation linkToAllocation=false time=allocation.modifyTime}} diff --git a/ui/mirage/factories/allocation.js b/ui/mirage/factories/allocation.js index 11bdff4d7..6c1c20393 100644 --- a/ui/mirage/factories/allocation.js +++ b/ui/mirage/factories/allocation.js @@ -66,7 +66,7 @@ export default Factory.extend({ // After rescheduleAttempts hits zero, a final allocation is made with no nextAllocation and // a clientStatus of failed or running, depending on rescheduleSuccess afterCreate(allocation, server) { - const attempts = allocation.rescheduleAttempts; + const attempts = allocation.rescheduleAttempts - 1; const previousEvents = (allocation.rescheduleTracker && allocation.rescheduleTracker.Events) || []; @@ -91,9 +91,9 @@ export default Factory.extend({ }; let nextAllocation; - if (attempts) { + if (attempts > 0) { nextAllocation = server.create('allocation', 'rescheduled', { - rescheduleAttempts: Math.max(attempts - 1, 0), + rescheduleAttempts: Math.max(attempts, 0), rescheduleSuccess: allocation.rescheduleSuccess, previousAllocation: allocation.id, clientStatus: 'failed', diff --git a/ui/tests/integration/reschedule-event-timeline-test.js b/ui/tests/integration/reschedule-event-timeline-test.js new file mode 100644 index 000000000..4bed776a0 --- /dev/null +++ b/ui/tests/integration/reschedule-event-timeline-test.js @@ -0,0 +1,198 @@ +import { getOwner } from '@ember/application'; +import { test, moduleForComponent } from 'ember-qunit'; +import { find, findAll } from 'ember-native-dom-helpers'; +import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; +import wait from 'ember-test-helpers/wait'; +import hbs from 'htmlbars-inline-precompile'; +import moment from 'moment'; + +moduleForComponent( + 'reschedule-event-timeline', + 'Integration | Component | reschedule event timeline', + { + integration: true, + beforeEach() { + this.store = getOwner(this).lookup('service:store'); + this.server = startMirage(); + this.server.create('namespace'); + this.server.create('node'); + this.server.create('job', { createAllocations: false }); + }, + afterEach() { + this.server.shutdown(); + }, + } +); + +const commonTemplate = hbs` + {{reschedule-event-timeline allocation=allocation}} +`; + +test('when the allocation is running, the timeline shows past allocations', function(assert) { + const attempts = 2; + + this.server.create('allocation', 'rescheduled', { + rescheduleAttempts: attempts, + rescheduleSuccess: true, + }); + + this.store.findAll('allocation'); + let allocation; + + return wait() + .then(() => { + allocation = this.store + .peekAll('allocation') + .find(alloc => !alloc.get('nextAllocation.content')); + + this.set('allocation', allocation); + this.render(commonTemplate); + + return wait(); + }) + .then(() => { + assert.equal( + findAll('[data-test-allocation]').length, + attempts + 1, + 'Total allocations equals current allocation plus all past allocations' + ); + assert.equal( + find('[data-test-allocation]'), + find(`[data-test-allocation="${allocation.id}"]`), + 'First allocation is the current allocation' + ); + + assert.notOk(find('[data-test-stop-warning]'), 'No stop warning'); + assert.notOk(find('[data-test-attempt-notice]'), 'No attempt notice'); + + assert.equal( + find( + `[data-test-allocation="${allocation.id}"] [data-test-allocation-link]` + ).textContent.trim(), + allocation.get('shortId'), + 'The "this" allocation is correct' + ); + assert.equal( + find( + `[data-test-allocation="${allocation.id}"] [data-test-allocation-status]` + ).textContent.trim(), + allocation.get('clientStatus'), + 'Allocation shows the status' + ); + }); +}); + +test('when the allocation has failed and there is a follow up evaluation, a note with a time is shown', function(assert) { + const attempts = 2; + + this.server.create('allocation', 'rescheduled', { + rescheduleAttempts: attempts, + rescheduleSuccess: false, + }); + + this.store.findAll('allocation'); + let allocation; + + return wait() + .then(() => { + allocation = this.store + .peekAll('allocation') + .find(alloc => !alloc.get('nextAllocation.content')); + + this.set('allocation', allocation); + this.render(commonTemplate); + + return wait(); + }) + .then(() => { + assert.ok( + find('[data-test-stop-warning]'), + 'Stop warning is shown since the last allocation failed' + ); + assert.notOk(find('[data-test-attempt-notice]'), 'Reschdule attempt notice is not shown'); + }); +}); + +test('when the allocation has failed and there is no follow up evaluation, a warning is shown', function(assert) { + const attempts = 2; + + this.server.create('allocation', 'rescheduled', { + rescheduleAttempts: attempts, + rescheduleSuccess: false, + }); + + const lastAllocation = server.schema.allocations.findBy({ nextAllocation: undefined }); + lastAllocation.update({ + followupEvalId: server.create('evaluation', { + waitUntil: moment() + .add(2, 'hours') + .toDate(), + }).id, + }); + + this.store.findAll('allocation'); + let allocation; + + return wait() + .then(() => { + allocation = this.store + .peekAll('allocation') + .find(alloc => !alloc.get('nextAllocation.content')); + + this.set('allocation', allocation); + this.render(commonTemplate); + + return wait(); + }) + .then(() => { + assert.ok( + find('[data-test-attempt-notice]'), + 'Reschedule notice is shown since the follow up eval says so' + ); + assert.notOk(find('[data-test-stop-warning]'), 'Stop warning is not shown'); + }); +}); + +test('when the allocation has a next allocation already, it is shown in the timeline', function(assert) { + const attempts = 2; + + const originalAllocation = this.server.create('allocation', 'rescheduled', { + rescheduleAttempts: attempts, + rescheduleSuccess: true, + }); + + this.store.findAll('allocation'); + let allocation; + + return wait() + .then(() => { + allocation = this.store.peekAll('allocation').findBy('id', originalAllocation.id); + + this.set('allocation', allocation); + this.render(commonTemplate); + + return wait(); + }) + .then(() => { + assert.ok( + find('[data-test-reschedule-label]').textContent.trim(), + 'Next Allocation', + 'The first allocation is the next allocation and labeled as such' + ); + + assert.equal( + find('[data-test-allocation] [data-test-allocation-link]').textContent.trim(), + allocation.get('nextAllocation.shortId'), + 'The next allocation item is for the correct allocation' + ); + + assert.equal( + findAll('[data-test-allocation]')[1], + find(`[data-test-allocation="${allocation.id}"]`), + 'Second allocation is the current allocation' + ); + + assert.notOk(find('[data-test-stop-warning]'), 'No stop warning'); + assert.notOk(find('[data-test-attempt-notice]'), 'No attempt notice'); + }); +});