import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; import generateResources from '../../../mirage/data/generate-resources'; import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; import { find, render } from '@ember/test-helpers'; import Response from 'ember-cli-mirage/response'; import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer'; import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; module('Integration | Component | allocation row', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { fragmentSerializerInitializer(this.owner); this.store = this.owner.lookup('service:store'); this.token = this.owner.lookup('service:token'); this.server = startMirage(); this.server.create('namespace'); this.server.create('node'); this.server.create('job', { createAllocations: false }); window.localStorage.clear(); }); hooks.afterEach(function() { this.server.shutdown(); }); test('Allocation row polls for stats, even when it errors or has an invalid response', async 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() }), ]; 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', { clientStatus: 'running' }); await this.store.findAll('allocation'); const allocation = this.store.peekAll('allocation').get('firstObject'); this.setProperties({ allocation, context: 'job', enablePolling: true, }); await render(hbs` `); 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' ); }); test('Allocation row shows warning when it requires drivers that are unhealthy on the node it is running on', async function(assert) { // Driver health status require node:read permission. const policy = server.create('policy', { id: 'node-read', name: 'node-read', rulesJSON: { Node: { Policy: 'read', }, }, }); const clientToken = server.create('token', { type: 'client' }); clientToken.policyIds = [policy.id]; clientToken.save(); // Set and fetch ACL token. window.localStorage.nomadTokenSecret = clientToken.secretId; this.token.fetchSelfTokenAndPolicies.perform(); const node = this.server.schema.nodes.first(); const drivers = node.drivers; Object.values(drivers).forEach(driver => { driver.Healthy = false; driver.Detected = true; }); node.update({ drivers }); this.server.create('allocation', { clientStatus: 'running' }); await this.store.findAll('job'); await this.store.findAll('node'); await this.store.findAll('allocation'); const allocation = this.store.peekAll('allocation').get('firstObject'); this.setProperties({ allocation, context: 'job', }); await render(hbs` `); assert.ok( find('[data-test-icon="unhealthy-driver"]'), 'Unhealthy driver icon is shown' ); await componentA11yAudit(this.element, assert); }); test('Allocation row shows an icon indicator when it was preempted', async function(assert) { const allocId = this.server.create('allocation', 'preempted').id; const allocation = await this.store.findRecord('allocation', allocId); this.setProperties({ allocation, context: 'job' }); await render(hbs` `); assert.ok(find('[data-test-icon="preemption"]'), 'Preempted icon is shown'); await componentA11yAudit(this.element, assert); }); test('when an allocation is not running, the utilization graphs are omitted', async function(assert) { this.setProperties({ context: 'job', enablePolling: false, }); // All non-running statuses need to be tested ['pending', 'complete', 'failed', 'lost'].forEach(clientStatus => this.server.create('allocation', { clientStatus }) ); await this.store.findAll('allocation'); const allocations = this.store.peekAll('allocation'); for (const allocation of allocations.toArray()) { this.set('allocation', allocation); await render(hbs` `); const status = allocation.get('clientStatus'); assert.notOk( find('[data-test-cpu] .inline-chart'), `No CPU chart for ${status}` ); assert.notOk( find('[data-test-mem] .inline-chart'), `No Mem chart for ${status}` ); } }); });