github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/ui/tests/acceptance/client-detail-test.js (about)

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