github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/acceptance/volume-detail-test.js (about)

     1  /* eslint-disable qunit/require-expect */
     2  import { module, test } from 'qunit';
     3  import { currentURL } from '@ember/test-helpers';
     4  import { setupApplicationTest } from 'ember-qunit';
     5  import { setupMirage } from 'ember-cli-mirage/test-support';
     6  import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
     7  import moment from 'moment';
     8  import { formatBytes, formatHertz } from 'nomad-ui/utils/units';
     9  import VolumeDetail from 'nomad-ui/tests/pages/storage/volumes/detail';
    10  import Layout from 'nomad-ui/tests/pages/layout';
    11  
    12  const assignWriteAlloc = (volume, alloc) => {
    13    volume.writeAllocs.add(alloc);
    14    volume.allocations.add(alloc);
    15    volume.save();
    16  };
    17  
    18  const assignReadAlloc = (volume, alloc) => {
    19    volume.readAllocs.add(alloc);
    20    volume.allocations.add(alloc);
    21    volume.save();
    22  };
    23  
    24  module('Acceptance | volume detail', function (hooks) {
    25    setupApplicationTest(hooks);
    26    setupMirage(hooks);
    27  
    28    let volume;
    29  
    30    hooks.beforeEach(function () {
    31      server.create('node');
    32      server.create('csi-plugin', { createVolumes: false });
    33      volume = server.create('csi-volume');
    34    });
    35  
    36    test('it passes an accessibility audit', async function (assert) {
    37      await VolumeDetail.visit({ id: `${volume.id}@default` });
    38      await a11yAudit(assert);
    39    });
    40  
    41    test('/csi/volumes/:id should have a breadcrumb trail linking back to Volumes and Storage', async function (assert) {
    42      await VolumeDetail.visit({ id: `${volume.id}@default` });
    43  
    44      assert.equal(Layout.breadcrumbFor('csi.index').text, 'Storage');
    45      assert.equal(Layout.breadcrumbFor('csi.volumes').text, 'Volumes');
    46      assert.equal(Layout.breadcrumbFor('csi.volumes.volume').text, volume.name);
    47    });
    48  
    49    test('/csi/volumes/:id should show the volume name in the title', async function (assert) {
    50      await VolumeDetail.visit({ id: `${volume.id}@default` });
    51  
    52      assert.equal(document.title, `CSI Volume ${volume.name} - Nomad`);
    53      assert.equal(VolumeDetail.title, volume.name);
    54    });
    55  
    56    test('/csi/volumes/:id should list additional details for the volume below the title', async function (assert) {
    57      await VolumeDetail.visit({ id: `${volume.id}@default` });
    58  
    59      assert.ok(
    60        VolumeDetail.health.includes(
    61          volume.schedulable ? 'Schedulable' : 'Unschedulable'
    62        )
    63      );
    64      assert.ok(VolumeDetail.provider.includes(volume.provider));
    65      assert.ok(VolumeDetail.externalId.includes(volume.externalId));
    66      assert.notOk(
    67        VolumeDetail.hasNamespace,
    68        'Namespace is omitted when there is only one namespace'
    69      );
    70    });
    71  
    72    test('/csi/volumes/:id should list all write allocations the volume is attached to', async function (assert) {
    73      const writeAllocations = server.createList('allocation', 2);
    74      const readAllocations = server.createList('allocation', 3);
    75      writeAllocations.forEach((alloc) => assignWriteAlloc(volume, alloc));
    76      readAllocations.forEach((alloc) => assignReadAlloc(volume, alloc));
    77  
    78      await VolumeDetail.visit({ id: `${volume.id}@default` });
    79  
    80      assert.equal(VolumeDetail.writeAllocations.length, writeAllocations.length);
    81      writeAllocations
    82        .sortBy('modifyIndex')
    83        .reverse()
    84        .forEach((allocation, idx) => {
    85          assert.equal(
    86            allocation.id,
    87            VolumeDetail.writeAllocations.objectAt(idx).id
    88          );
    89        });
    90    });
    91  
    92    test('/csi/volumes/:id should list all read allocations the volume is attached to', async function (assert) {
    93      const writeAllocations = server.createList('allocation', 2);
    94      const readAllocations = server.createList('allocation', 3);
    95      writeAllocations.forEach((alloc) => assignWriteAlloc(volume, alloc));
    96      readAllocations.forEach((alloc) => assignReadAlloc(volume, alloc));
    97  
    98      await VolumeDetail.visit({ id: `${volume.id}@default` });
    99  
   100      assert.equal(VolumeDetail.readAllocations.length, readAllocations.length);
   101      readAllocations
   102        .sortBy('modifyIndex')
   103        .reverse()
   104        .forEach((allocation, idx) => {
   105          assert.equal(
   106            allocation.id,
   107            VolumeDetail.readAllocations.objectAt(idx).id
   108          );
   109        });
   110    });
   111  
   112    test('each allocation should have high-level details for the allocation', async function (assert) {
   113      const allocation = server.create('allocation', { clientStatus: 'running' });
   114      assignWriteAlloc(volume, allocation);
   115  
   116      const allocStats = server.db.clientAllocationStats.find(allocation.id);
   117      const taskGroup = server.db.taskGroups.findBy({
   118        name: allocation.taskGroup,
   119        jobId: allocation.jobId,
   120      });
   121  
   122      const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
   123      const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0);
   124      const memoryUsed = tasks.reduce(
   125        (sum, task) => sum + task.resources.MemoryMB,
   126        0
   127      );
   128  
   129      await VolumeDetail.visit({ id: `${volume.id}@default` });
   130  
   131      VolumeDetail.writeAllocations.objectAt(0).as((allocationRow) => {
   132        assert.equal(
   133          allocationRow.shortId,
   134          allocation.id.split('-')[0],
   135          'Allocation short ID'
   136        );
   137        assert.equal(
   138          allocationRow.createTime,
   139          moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ'),
   140          'Allocation create time'
   141        );
   142        assert.equal(
   143          allocationRow.modifyTime,
   144          moment(allocation.modifyTime / 1000000).fromNow(),
   145          'Allocation modify time'
   146        );
   147        assert.equal(
   148          allocationRow.status,
   149          allocation.clientStatus,
   150          'Client status'
   151        );
   152        assert.equal(
   153          allocationRow.job,
   154          server.db.jobs.find(allocation.jobId).name,
   155          'Job name'
   156        );
   157        assert.ok(allocationRow.taskGroup, 'Task group name');
   158        assert.ok(allocationRow.jobVersion, 'Job Version');
   159        assert.equal(
   160          allocationRow.client,
   161          server.db.nodes.find(allocation.nodeId).id.split('-')[0],
   162          'Node ID'
   163        );
   164        assert.equal(
   165          allocationRow.clientTooltip.substr(0, 15),
   166          server.db.nodes.find(allocation.nodeId).name.substr(0, 15),
   167          'Node Name'
   168        );
   169        assert.equal(
   170          allocationRow.cpu,
   171          Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed,
   172          'CPU %'
   173        );
   174        const roundedTicks = Math.floor(
   175          allocStats.resourceUsage.CpuStats.TotalTicks
   176        );
   177        assert.equal(
   178          allocationRow.cpuTooltip,
   179          `${formatHertz(roundedTicks, 'MHz')} / ${formatHertz(cpuUsed, 'MHz')}`,
   180          'Detailed CPU information is in a tooltip'
   181        );
   182        assert.equal(
   183          allocationRow.mem,
   184          allocStats.resourceUsage.MemoryStats.RSS / 1024 / 1024 / memoryUsed,
   185          'Memory used'
   186        );
   187        assert.equal(
   188          allocationRow.memTooltip,
   189          `${formatBytes(
   190            allocStats.resourceUsage.MemoryStats.RSS
   191          )} / ${formatBytes(memoryUsed, 'MiB')}`,
   192          'Detailed memory information is in a tooltip'
   193        );
   194      });
   195    });
   196  
   197    test('each allocation should link to the allocation detail page', async function (assert) {
   198      const allocation = server.create('allocation');
   199      assignWriteAlloc(volume, allocation);
   200  
   201      await VolumeDetail.visit({ id: `${volume.id}@default` });
   202      await VolumeDetail.writeAllocations.objectAt(0).visit();
   203  
   204      assert.equal(currentURL(), `/allocations/${allocation.id}`);
   205    });
   206  
   207    test('when there are no write allocations, the table presents an empty state', async function (assert) {
   208      await VolumeDetail.visit({ id: `${volume.id}@default` });
   209  
   210      assert.ok(VolumeDetail.writeTableIsEmpty);
   211      assert.equal(VolumeDetail.writeEmptyState.headline, 'No Write Allocations');
   212    });
   213  
   214    test('when there are no read allocations, the table presents an empty state', async function (assert) {
   215      await VolumeDetail.visit({ id: `${volume.id}@default` });
   216  
   217      assert.ok(VolumeDetail.readTableIsEmpty);
   218      assert.equal(VolumeDetail.readEmptyState.headline, 'No Read Allocations');
   219    });
   220  
   221    test('the constraints table shows access mode and attachment mode', async function (assert) {
   222      await VolumeDetail.visit({ id: `${volume.id}@default` });
   223  
   224      assert.equal(VolumeDetail.constraints.accessMode, volume.accessMode);
   225      assert.equal(
   226        VolumeDetail.constraints.attachmentMode,
   227        volume.attachmentMode
   228      );
   229    });
   230  });
   231  
   232  // Namespace test: details shows the namespace
   233  module('Acceptance | volume detail (with namespaces)', function (hooks) {
   234    setupApplicationTest(hooks);
   235    setupMirage(hooks);
   236  
   237    let volume;
   238  
   239    hooks.beforeEach(function () {
   240      server.createList('namespace', 2);
   241      server.create('node');
   242      server.create('csi-plugin', { createVolumes: false });
   243      volume = server.create('csi-volume');
   244    });
   245  
   246    test('/csi/volumes/:id detail ribbon includes the namespace of the volume', async function (assert) {
   247      await VolumeDetail.visit({ id: `${volume.id}@${volume.namespaceId}` });
   248  
   249      assert.ok(VolumeDetail.hasNamespace);
   250      assert.ok(VolumeDetail.namespace.includes(volume.namespaceId || 'default'));
   251    });
   252  });