diff --git a/ui/app/components/allocation-row.js b/ui/app/components/allocation-row.js index bf00d4cb5..d6236d6a2 100644 --- a/ui/app/components/allocation-row.js +++ b/ui/app/components/allocation-row.js @@ -1,6 +1,7 @@ import Ember from 'ember'; import { inject as service } from '@ember/service'; import Component from '@ember/component'; +import { computed } from '@ember/object'; import { run } from '@ember/runloop'; import { lazyClick } from '../helpers/lazy-click'; import { task, timeout } from 'ember-concurrency'; @@ -17,10 +18,14 @@ export default Component.extend({ // Used to determine whether the row should mention the node or the job context: null, + backoffSequence: computed(() => [500, 800, 1300, 2100, 3400, 5500]), + // Internal state stats: null, statsError: false, + enablePolling: computed(() => !Ember.testing), + onClick() {}, click(event) { @@ -63,8 +68,8 @@ export default Component.extend({ }, fetchStats: task(function*(allocation) { - const maxTiming = 5500; - const backoffSequence = [500, 800, 1300, 2100, 3400]; + const backoffSequence = this.get('backoffSequence').slice(); + const maxTiming = backoffSequence.pop(); do { try { @@ -75,7 +80,7 @@ export default Component.extend({ this.set('statsError', true); } yield timeout(backoffSequence.shift() || maxTiming); - } while (!Ember.testing); + } while (this.get('enablePolling')); }).drop(), }); diff --git a/ui/mirage/config.js b/ui/mirage/config.js index 6731f341c..f28d9e746 100644 --- a/ui/mirage/config.js +++ b/ui/mirage/config.js @@ -132,6 +132,8 @@ export default function() { return this.serialize(allocations.where({ nodeId: params.id })); }); + this.get('/allocations'); + this.get('/allocation/:id'); this.get('/namespaces', function({ namespaces }) { diff --git a/ui/tests/integration/allocation-row-test.js b/ui/tests/integration/allocation-row-test.js new file mode 100644 index 000000000..dd6478f40 --- /dev/null +++ b/ui/tests/integration/allocation-row-test.js @@ -0,0 +1,85 @@ +import { getOwner } from '@ember/application'; +import { test, moduleForComponent } from 'ember-qunit'; +import wait from 'ember-test-helpers/wait'; +import hbs from 'htmlbars-inline-precompile'; +import generateResources from '../../mirage/data/generate-resources'; +import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; +import Response from 'ember-cli-mirage/response'; + +moduleForComponent('allocation-row', 'Integration | Component | allocation row', { + 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(); + }, +}); + +test('Allocation row polls for stats, even when it errors or has an invalid response', function(assert) { + const component = this; + + let currentFrame = 0; + let frames = [ + JSON.stringify({ ResourceUsage: generateResources() }), + JSON.stringify({ ResourceUsage: generateResources() }), + null, + 'Valid JSON', + JSON.stringify({ ResourceUsage: generateResources() }), + ]; + const backoffSequence = [50]; + + this.server.get('/client/allocation/:id/stats', function() { + const response = frames[++currentFrame]; + + // Disable polling to stop the EC task in the component + if (currentFrame >= frames.length) { + component.set('enablePolling', false); + } + + if (response) { + return response; + } + return new Response(500, {}, ''); + }); + + this.server.create('allocation'); + this.store.findAll('allocation'); + + let allocation; + + return wait() + .then(() => { + allocation = this.store.peekAll('allocation').get('firstObject'); + + this.setProperties({ + allocation, + backoffSequence, + context: 'job', + enablePolling: true, + }); + + this.render(hbs` + {{allocation-row + allocation=allocation + context=context + backoffSequence=backoffSequence + enablePolling=enablePolling}} + `); + return wait(); + }) + .then(() => { + assert.equal( + this.server.pretender.handledRequests.filterBy( + 'url', + `/v1/client/allocation/${allocation.get('id')}/stats` + ).length, + frames.length, + 'Requests continue to be made after malformed responses and server errors' + ); + }); +});