github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/ui/tests/acceptance/client-detail-test.js (about)

     1  import Ember from 'ember';
     2  import { click, find, findAll, currentURL, visit } from 'ember-native-dom-helpers';
     3  import { test } from 'qunit';
     4  import moduleForAcceptance from 'nomad-ui/tests/helpers/module-for-acceptance';
     5  import { formatBytes } from 'nomad-ui/helpers/format-bytes';
     6  import moment from 'moment';
     7  
     8  const { $ } = Ember;
     9  
    10  let node;
    11  
    12  moduleForAcceptance('Acceptance | client detail', {
    13    beforeEach() {
    14      server.create('node', 'forceIPv4');
    15      node = server.db.nodes[0];
    16  
    17      // Related models
    18      server.create('agent');
    19      server.create('job', { createAllocations: false });
    20      server.createList('allocation', 3, { nodeId: node.id });
    21    },
    22  });
    23  
    24  test('/clients/:id should have a breadrcumb trail linking back to clients', function(assert) {
    25    visit(`/clients/${node.id}`);
    26  
    27    andThen(() => {
    28      assert.equal(findAll('.breadcrumb')[0].textContent, 'Clients', 'First breadcrumb says clients');
    29      assert.equal(
    30        findAll('.breadcrumb')[1].textContent,
    31        node.id.split('-')[0],
    32        'Second breadcrumb says the node short id'
    33      );
    34    });
    35  
    36    andThen(() => {
    37      click(findAll('.breadcrumb')[0]);
    38    });
    39  
    40    andThen(() => {
    41      assert.equal(currentURL(), '/clients', 'First breadcrumb links back to clients');
    42    });
    43  });
    44  
    45  test('/clients/:id should list immediate details for the node in the title', function(assert) {
    46    visit(`/clients/${node.id}`);
    47  
    48    andThen(() => {
    49      assert.ok(find('.title').textContent.includes(node.name), 'Title includes name');
    50      assert.ok(find('.title').textContent.includes(node.id), 'Title includes id');
    51      assert.ok(
    52        findAll(`.title .node-status-light.${node.status}`).length,
    53        'Title includes status light'
    54      );
    55    });
    56  });
    57  
    58  test('/clients/:id should list additional detail for the node below the title', function(assert) {
    59    visit(`/clients/${node.id}`);
    60  
    61    andThen(() => {
    62      assert.equal(
    63        findAll('.inline-definitions .pair')[0].textContent,
    64        `Status ${node.status}`,
    65        'Status is in additional details'
    66      );
    67      assert.ok(
    68        $('.inline-definitions .pair:eq(0) .status-text').hasClass(`node-${node.status}`),
    69        'Status is decorated with a status class'
    70      );
    71      assert.equal(
    72        findAll('.inline-definitions .pair')[1].textContent,
    73        `Address ${node.httpAddr}`,
    74        'Address is in additional detals'
    75      );
    76      assert.equal(
    77        findAll('.inline-definitions .pair')[2].textContent,
    78        `Datacenter ${node.datacenter}`,
    79        'Datacenter is in additional details'
    80      );
    81    });
    82  });
    83  
    84  test('/clients/:id should list all allocations on the node', function(assert) {
    85    const allocationsCount = server.db.allocations.where({ nodeId: node.id }).length;
    86  
    87    visit(`/clients/${node.id}`);
    88  
    89    andThen(() => {
    90      assert.equal(
    91        findAll('.allocations tbody tr').length,
    92        allocationsCount,
    93        `Allocations table lists all ${allocationsCount} associated allocations`
    94      );
    95    });
    96  });
    97  
    98  test('each allocation should have high-level details for the allocation', function(assert) {
    99    const allocation = server.db.allocations
   100      .where({ nodeId: node.id })
   101      .sortBy('modifyIndex')
   102      .reverse()[0];
   103  
   104    const allocStats = server.db.clientAllocationStats.find(allocation.id);
   105    const taskGroup = server.db.taskGroups.findBy({
   106      name: allocation.taskGroup,
   107      jobId: allocation.jobId,
   108    });
   109  
   110    const tasks = taskGroup.taskIds.map(id => server.db.tasks.find(id));
   111    const cpuUsed = tasks.reduce((sum, task) => sum + task.Resources.CPU, 0);
   112    const memoryUsed = tasks.reduce((sum, task) => sum + task.Resources.MemoryMB, 0);
   113  
   114    visit(`/clients/${node.id}`);
   115  
   116    andThen(() => {
   117      const allocationRow = $(findAll('.allocations tbody tr')[0]);
   118      assert.equal(
   119        allocationRow
   120          .find('td:eq(0)')
   121          .text()
   122          .trim(),
   123        allocation.id.split('-')[0],
   124        'Allocation short ID'
   125      );
   126      assert.equal(
   127        allocationRow
   128          .find('td:eq(1)')
   129          .text()
   130          .trim(),
   131        moment(allocation.modifyTime / 1000000).format('MM/DD HH:mm:ss'),
   132        'Allocation modify time'
   133      );
   134      assert.equal(
   135        allocationRow
   136          .find('td:eq(2)')
   137          .text()
   138          .trim(),
   139        allocation.name,
   140        'Allocation name'
   141      );
   142      assert.equal(
   143        allocationRow
   144          .find('td:eq(3)')
   145          .text()
   146          .trim(),
   147        allocation.clientStatus,
   148        'Client status'
   149      );
   150      assert.ok(
   151        allocationRow
   152          .find('td:eq(4)')
   153          .text()
   154          .includes(server.db.jobs.find(allocation.jobId).name),
   155        'Job name'
   156      );
   157      assert.ok(
   158        allocationRow
   159          .find('td:eq(4) .is-faded')
   160          .text()
   161          .includes(allocation.taskGroup),
   162        'Task group name'
   163      );
   164      assert.ok(
   165        allocationRow
   166          .find('td:eq(5)')
   167          .text()
   168          .includes(allocation.jobVersion),
   169        'Job Version'
   170      );
   171      assert.equal(
   172        allocationRow
   173          .find('td:eq(6)')
   174          .text()
   175          .trim(),
   176        Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed,
   177        'CPU %'
   178      );
   179      assert.equal(
   180        allocationRow.find('td:eq(6) .tooltip').attr('aria-label'),
   181        `${Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks)} / ${cpuUsed} MHz`,
   182        'Detailed CPU information is in a tooltip'
   183      );
   184      assert.equal(
   185        allocationRow
   186          .find('td:eq(7)')
   187          .text()
   188          .trim(),
   189        allocStats.resourceUsage.MemoryStats.RSS / 1024 / 1024 / memoryUsed,
   190        'Memory used'
   191      );
   192      assert.equal(
   193        allocationRow.find('td:eq(7) .tooltip').attr('aria-label'),
   194        `${formatBytes([allocStats.resourceUsage.MemoryStats.RSS])} / ${memoryUsed} MiB`,
   195        'Detailed memory information is in a tooltip'
   196      );
   197    });
   198  });
   199  
   200  test('each allocation should show job information even if the job is incomplete and already in the store', function(
   201    assert
   202  ) {
   203    // First, visit clients to load the allocations for each visible node.
   204    // Don't load the job belongsTo of the allocation! Leave it unfulfilled.
   205  
   206    visit('/clients');
   207  
   208    // Then, visit jobs to load all jobs, which should implicitly fulfill
   209    // the job belongsTo of each allocation pointed at each job.
   210  
   211    visit('/jobs');
   212  
   213    // Finally, visit a node to assert that the job name and task group name are
   214    // present. This will require reloading the job, since task groups aren't a
   215    // part of the jobs list response.
   216  
   217    visit(`/clients/${node.id}`);
   218  
   219    andThen(() => {
   220      const allocationRow = $(findAll('.allocations tbody tr')[0]);
   221      const allocation = server.db.allocations
   222        .where({ nodeId: node.id })
   223        .sortBy('modifyIndex')
   224        .reverse()[0];
   225  
   226      assert.ok(
   227        allocationRow
   228          .find('td:eq(4)')
   229          .text()
   230          .includes(server.db.jobs.find(allocation.jobId).name),
   231        'Job name'
   232      );
   233      assert.ok(
   234        allocationRow
   235          .find('td:eq(4) .is-faded')
   236          .text()
   237          .includes(allocation.taskGroup),
   238        'Task group name'
   239      );
   240    });
   241  });
   242  
   243  test('each allocation should link to the allocation detail page', function(assert) {
   244    const allocation = server.db.allocations
   245      .where({ nodeId: node.id })
   246      .sortBy('modifyIndex')
   247      .reverse()[0];
   248  
   249    visit(`/clients/${node.id}`);
   250  
   251    andThen(() => {
   252      click($('.allocations tbody tr:eq(0) td:eq(0) a').get(0));
   253    });
   254  
   255    andThen(() => {
   256      assert.equal(
   257        currentURL(),
   258        `/allocations/${allocation.id}`,
   259        'Allocation rows link to allocation detail pages'
   260      );
   261    });
   262  });
   263  
   264  test('each allocation should link to the job the allocation belongs to', function(assert) {
   265    visit(`/clients/${node.id}`);
   266  
   267    const allocation = server.db.allocations.where({ nodeId: node.id })[0];
   268    const job = server.db.jobs.find(allocation.jobId);
   269  
   270    andThen(() => {
   271      click($('.allocations tbody tr:eq(0) td:eq(4) a').get(0));
   272    });
   273  
   274    andThen(() => {
   275      assert.equal(
   276        currentURL(),
   277        `/jobs/${job.id}`,
   278        'Allocation rows link to the job detail page for the allocation'
   279      );
   280    });
   281  });
   282  
   283  test('/clients/:id should list all attributes for the node', function(assert) {
   284    visit(`/clients/${node.id}`);
   285  
   286    andThen(() => {
   287      assert.ok(find('.attributes-table'), 'Attributes table is on the page');
   288    });
   289  });
   290  
   291  test('when the node is not found, an error message is shown, but the URL persists', function(
   292    assert
   293  ) {
   294    visit('/clients/not-a-real-node');
   295  
   296    andThen(() => {
   297      assert.equal(
   298        server.pretender.handledRequests.findBy('status', 404).url,
   299        '/v1/node/not-a-real-node',
   300        'A request to the non-existent node is made'
   301      );
   302      assert.equal(currentURL(), '/clients/not-a-real-node', 'The URL persists');
   303      assert.ok(find('.error-message'), 'Error message is shown');
   304      assert.equal(
   305        find('.error-message .title').textContent,
   306        'Not Found',
   307        'Error message is for 404'
   308      );
   309    });
   310  });