github.com/ferranbt/nomad@v0.9.3-0.20190607002617-85c449b7667c/ui/tests/acceptance/allocation-detail-test.js (about)

     1  import { run } from '@ember/runloop';
     2  import { currentURL } from '@ember/test-helpers';
     3  import { assign } from '@ember/polyfills';
     4  import { module, test } from 'qunit';
     5  import { setupApplicationTest } from 'ember-qunit';
     6  import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
     7  import Allocation from 'nomad-ui/tests/pages/allocations/detail';
     8  import moment from 'moment';
     9  
    10  let job;
    11  let node;
    12  let allocation;
    13  
    14  module('Acceptance | allocation detail', function(hooks) {
    15    setupApplicationTest(hooks);
    16    setupMirage(hooks);
    17  
    18    hooks.beforeEach(async function() {
    19      server.create('agent');
    20  
    21      node = server.create('node');
    22      job = server.create('job', { groupsCount: 1, createAllocations: false });
    23      allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'running' });
    24  
    25      // Make sure the node has an unhealthy driver
    26      node.update({
    27        driver: assign(node.drivers, {
    28          docker: {
    29            detected: true,
    30            healthy: false,
    31          },
    32        }),
    33      });
    34  
    35      // Make sure a task for the allocation depends on the unhealthy driver
    36      server.schema.tasks.first().update({
    37        driver: 'docker',
    38      });
    39  
    40      await Allocation.visit({ id: allocation.id });
    41    });
    42  
    43    test('/allocation/:id should name the allocation and link to the corresponding job and node', async function(assert) {
    44      assert.ok(Allocation.title.includes(allocation.name), 'Allocation name is in the heading');
    45      assert.equal(Allocation.details.job, job.name, 'Job name is in the subheading');
    46      assert.equal(
    47        Allocation.details.client,
    48        node.id.split('-')[0],
    49        'Node short id is in the subheading'
    50      );
    51  
    52      await Allocation.details.visitJob();
    53      assert.equal(currentURL(), `/jobs/${job.id}`, 'Job link navigates to the job');
    54  
    55      await Allocation.visit({ id: allocation.id });
    56  
    57      await Allocation.details.visitClient();
    58      assert.equal(currentURL(), `/clients/${node.id}`, 'Client link navigates to the client');
    59    });
    60  
    61    test('/allocation/:id should include resource utilization graphs', async function(assert) {
    62      assert.equal(Allocation.resourceCharts.length, 2, 'Two resource utilization graphs');
    63      assert.equal(Allocation.resourceCharts.objectAt(0).name, 'CPU', 'First chart is CPU');
    64      assert.equal(Allocation.resourceCharts.objectAt(1).name, 'Memory', 'Second chart is Memory');
    65    });
    66  
    67    test('/allocation/:id should list all tasks for the allocation', async function(assert) {
    68      assert.equal(
    69        Allocation.tasks.length,
    70        server.db.taskStates.where({ allocationId: allocation.id }).length,
    71        'Table lists all tasks'
    72      );
    73      assert.notOk(Allocation.isEmpty, 'Task table empty state is not shown');
    74    });
    75  
    76    test('each task row should list high-level information for the task', async function(assert) {
    77      const task = server.db.taskStates.where({ allocationId: allocation.id }).sortBy('name')[0];
    78      const taskResources = allocation.taskResourceIds
    79        .map(id => server.db.taskResources.find(id))
    80        .sortBy('name')[0];
    81      const reservedPorts = taskResources.resources.Networks[0].ReservedPorts;
    82      const dynamicPorts = taskResources.resources.Networks[0].DynamicPorts;
    83      const taskRow = Allocation.tasks.objectAt(0);
    84      const events = server.db.taskEvents.where({ taskStateId: task.id });
    85      const event = events[events.length - 1];
    86  
    87      assert.equal(taskRow.name, task.name, 'Name');
    88      assert.equal(taskRow.state, task.state, 'State');
    89      assert.equal(taskRow.message, event.displayMessage, 'Event Message');
    90      assert.equal(
    91        taskRow.time,
    92        moment(event.time / 1000000).format("MMM DD, 'YY HH:mm:ss ZZ"),
    93        'Event Time'
    94      );
    95  
    96      assert.ok(reservedPorts.length, 'The task has reserved ports');
    97      assert.ok(dynamicPorts.length, 'The task has dynamic ports');
    98  
    99      const addressesText = taskRow.ports;
   100      reservedPorts.forEach(port => {
   101        assert.ok(addressesText.includes(port.Label), `Found label ${port.Label}`);
   102        assert.ok(addressesText.includes(port.Value), `Found value ${port.Value}`);
   103      });
   104      dynamicPorts.forEach(port => {
   105        assert.ok(addressesText.includes(port.Label), `Found label ${port.Label}`);
   106        assert.ok(addressesText.includes(port.Value), `Found value ${port.Value}`);
   107      });
   108    });
   109  
   110    test('each task row should link to the task detail page', async function(assert) {
   111      const task = server.db.taskStates.where({ allocationId: allocation.id }).sortBy('name')[0];
   112  
   113      await Allocation.tasks.objectAt(0).clickLink();
   114  
   115      assert.equal(
   116        currentURL(),
   117        `/allocations/${allocation.id}/${task.name}`,
   118        'Task name in task row links to task detail'
   119      );
   120  
   121      await Allocation.visit({ id: allocation.id });
   122      await Allocation.tasks.objectAt(0).clickRow();
   123  
   124      assert.equal(
   125        currentURL(),
   126        `/allocations/${allocation.id}/${task.name}`,
   127        'Task row links to task detail'
   128      );
   129    });
   130  
   131    test('tasks with an unhealthy driver have a warning icon', async function(assert) {
   132      assert.ok(Allocation.firstUnhealthyTask().hasUnhealthyDriver, 'Warning is shown');
   133    });
   134  
   135    test('when there are no tasks, an empty state is shown', async function(assert) {
   136      // Make sure the allocation is pending in order to ensure there are no tasks
   137      allocation = server.create('allocation', 'withTaskWithPorts', { clientStatus: 'pending' });
   138      await Allocation.visit({ id: allocation.id });
   139  
   140      assert.ok(Allocation.isEmpty, 'Task table empty state is shown');
   141    });
   142  
   143    test('when the allocation has not been rescheduled, the reschedule events section is not rendered', async function(assert) {
   144      assert.notOk(Allocation.hasRescheduleEvents, 'Reschedule Events section exists');
   145    });
   146  
   147    test('when the allocation is not found, an error message is shown, but the URL persists', async function(assert) {
   148      await Allocation.visit({ id: 'not-a-real-allocation' });
   149  
   150      assert.equal(
   151        server.pretender.handledRequests.findBy('status', 404).url,
   152        '/v1/allocation/not-a-real-allocation',
   153        'A request to the nonexistent allocation is made'
   154      );
   155      assert.equal(currentURL(), '/allocations/not-a-real-allocation', 'The URL persists');
   156      assert.ok(Allocation.error.isShown, 'Error message is shown');
   157      assert.equal(Allocation.error.title, 'Not Found', 'Error message is for 404');
   158    });
   159  
   160    test('allocation can be stopped', async function(assert) {
   161      await Allocation.stop.idle();
   162      await Allocation.stop.confirm();
   163  
   164      assert.equal(
   165        server.pretender.handledRequests.findBy('method', 'POST').url,
   166        `/v1/allocation/${allocation.id}/stop`,
   167        'Stop request is made for the allocation'
   168      );
   169    });
   170  
   171    test('allocation can be restarted', async function(assert) {
   172      await Allocation.restart.idle();
   173      await Allocation.restart.confirm();
   174  
   175      assert.equal(
   176        server.pretender.handledRequests.findBy('method', 'PUT').url,
   177        `/v1/client/allocation/${allocation.id}/restart`,
   178        'Restart request is made for the allocation'
   179      );
   180    });
   181  
   182    test('while an allocation is being restarted, the stop button is disabled', async function(assert) {
   183      server.pretender.post('/v1/allocation/:id/stop', () => [204, {}, ''], true);
   184  
   185      await Allocation.stop.idle();
   186  
   187      run.later(() => {
   188        assert.ok(Allocation.stop.isRunning, 'Stop is loading');
   189        assert.ok(Allocation.restart.isDisabled, 'Restart is disabled');
   190        server.pretender.resolve(server.pretender.requestReferences[0].request);
   191      }, 500);
   192  
   193      await Allocation.stop.confirm();
   194    });
   195  
   196    test('if stopping or restarting fails, an error message is shown', async function(assert) {
   197      server.pretender.post('/v1/allocation/:id/stop', () => [403, {}, '']);
   198  
   199      await Allocation.stop.idle();
   200      await Allocation.stop.confirm();
   201  
   202      assert.ok(Allocation.inlineError.isShown, 'Inline error is shown');
   203      assert.ok(
   204        Allocation.inlineError.title.includes('Could Not Stop Allocation'),
   205        'Title is descriptive'
   206      );
   207      assert.ok(
   208        /ACL token.+?allocation lifecycle/.test(Allocation.inlineError.message),
   209        'Message mentions ACLs and the appropriate permission'
   210      );
   211  
   212      await Allocation.inlineError.dismiss();
   213  
   214      assert.notOk(Allocation.inlineError.isShown, 'Inline error is no longer shown');
   215    });
   216  });
   217  
   218  module('Acceptance | allocation detail (rescheduled)', function(hooks) {
   219    setupApplicationTest(hooks);
   220    setupMirage(hooks);
   221  
   222    hooks.beforeEach(async function() {
   223      server.create('agent');
   224  
   225      node = server.create('node');
   226      job = server.create('job', { createAllocations: false });
   227      allocation = server.create('allocation', 'rescheduled');
   228  
   229      await Allocation.visit({ id: allocation.id });
   230    });
   231  
   232    test('when the allocation has been rescheduled, the reschedule events section is rendered', async function(assert) {
   233      assert.ok(Allocation.hasRescheduleEvents, 'Reschedule Events section exists');
   234    });
   235  });
   236  
   237  module('Acceptance | allocation detail (not running)', function(hooks) {
   238    setupApplicationTest(hooks);
   239    setupMirage(hooks);
   240  
   241    hooks.beforeEach(async function() {
   242      server.create('agent');
   243  
   244      node = server.create('node');
   245      job = server.create('job', { createAllocations: false });
   246      allocation = server.create('allocation', { clientStatus: 'pending' });
   247  
   248      await Allocation.visit({ id: allocation.id });
   249    });
   250  
   251    test('when the allocation is not running, the utilization graphs are replaced by an empty message', async function(assert) {
   252      assert.equal(Allocation.resourceCharts.length, 0, 'No resource charts');
   253      assert.equal(
   254        Allocation.resourceEmptyMessage,
   255        "Allocation isn't running",
   256        'Empty message is appropriate'
   257      );
   258    });
   259  });
   260  
   261  module('Acceptance | allocation detail (preemptions)', function(hooks) {
   262    setupApplicationTest(hooks);
   263    setupMirage(hooks);
   264  
   265    hooks.beforeEach(async function() {
   266      server.create('agent');
   267      node = server.create('node');
   268      job = server.create('job', { createAllocations: false });
   269    });
   270  
   271    test('shows a dedicated section to the allocation that preempted this allocation', async function(assert) {
   272      allocation = server.create('allocation', 'preempted');
   273      const preempter = server.schema.find('allocation', allocation.preemptedByAllocation);
   274      const preempterJob = server.schema.find('job', preempter.jobId);
   275      const preempterClient = server.schema.find('node', preempter.nodeId);
   276  
   277      await Allocation.visit({ id: allocation.id });
   278      assert.ok(Allocation.wasPreempted, 'Preempted allocation section is shown');
   279      assert.equal(Allocation.preempter.status, preempter.clientStatus, 'Preempter status matches');
   280      assert.equal(Allocation.preempter.name, preempter.name, 'Preempter name matches');
   281      assert.equal(
   282        Allocation.preempter.priority,
   283        preempterJob.priority,
   284        'Preempter priority matches'
   285      );
   286  
   287      await Allocation.preempter.visit();
   288      assert.equal(
   289        currentURL(),
   290        `/allocations/${preempter.id}`,
   291        'Clicking the preempter id navigates to the preempter allocation detail page'
   292      );
   293  
   294      await Allocation.visit({ id: allocation.id });
   295      await Allocation.preempter.visitJob();
   296      assert.equal(
   297        currentURL(),
   298        `/jobs/${preempterJob.id}`,
   299        'Clicking the preempter job link navigates to the preempter job page'
   300      );
   301  
   302      await Allocation.visit({ id: allocation.id });
   303      await Allocation.preempter.visitClient();
   304      assert.equal(
   305        currentURL(),
   306        `/clients/${preempterClient.id}`,
   307        'Clicking the preempter client link navigates to the preempter client page'
   308      );
   309    });
   310  
   311    test('shows a dedicated section to the allocations this allocation preempted', async function(assert) {
   312      allocation = server.create('allocation', 'preempter');
   313      await Allocation.visit({ id: allocation.id });
   314      assert.ok(Allocation.preempted, 'The allocations this allocation preempted are shown');
   315    });
   316  
   317    test('each preempted allocation in the table lists basic allocation information', async function(assert) {
   318      allocation = server.create('allocation', 'preempter');
   319      await Allocation.visit({ id: allocation.id });
   320  
   321      const preemption = allocation.preemptedAllocations
   322        .map(id => server.schema.find('allocation', id))
   323        .sortBy('modifyIndex')
   324        .reverse()[0];
   325      const preemptionRow = Allocation.preemptions.objectAt(0);
   326  
   327      assert.equal(
   328        Allocation.preemptions.length,
   329        allocation.preemptedAllocations.length,
   330        'The preemptions table has a row for each preempted allocation'
   331      );
   332  
   333      assert.equal(preemptionRow.shortId, preemption.id.split('-')[0], 'Preemption short id');
   334      assert.equal(
   335        preemptionRow.createTime,
   336        moment(preemption.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'),
   337        'Preemption create time'
   338      );
   339      assert.equal(
   340        preemptionRow.modifyTime,
   341        moment(preemption.modifyTime / 1000000).fromNow(),
   342        'Preemption modify time'
   343      );
   344      assert.equal(preemptionRow.status, preemption.clientStatus, 'Client status');
   345      assert.equal(preemptionRow.jobVersion, preemption.jobVersion, 'Job Version');
   346      assert.equal(
   347        preemptionRow.client,
   348        server.db.nodes.find(preemption.nodeId).id.split('-')[0],
   349        'Node ID'
   350      );
   351  
   352      await preemptionRow.visitClient();
   353      assert.equal(currentURL(), `/clients/${preemption.nodeId}`, 'Node links to node page');
   354    });
   355  
   356    test('when an allocation both preempted allocations and was preempted itself, both preemptions sections are shown', async function(assert) {
   357      allocation = server.create('allocation', 'preempter', 'preempted');
   358      await Allocation.visit({ id: allocation.id });
   359      assert.ok(Allocation.preempted, 'The allocations this allocation preempted are shown');
   360      assert.ok(Allocation.wasPreempted, 'Preempted allocation section is shown');
   361    });
   362  });