github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/acceptance/plugin-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 PluginDetail from 'nomad-ui/tests/pages/storage/plugins/detail';
    10  import Layout from 'nomad-ui/tests/pages/layout';
    11  
    12  module('Acceptance | plugin detail', function (hooks) {
    13    setupApplicationTest(hooks);
    14    setupMirage(hooks);
    15  
    16    let plugin;
    17  
    18    hooks.beforeEach(function () {
    19      server.create('node');
    20      plugin = server.create('csi-plugin', { controllerRequired: true });
    21    });
    22  
    23    test('it passes an accessibility audit', async function (assert) {
    24      await PluginDetail.visit({ id: plugin.id });
    25      await a11yAudit(assert);
    26    });
    27  
    28    test('/csi/plugins/:id should have a breadcrumb trail linking back to Plugins and Storage', async function (assert) {
    29      await PluginDetail.visit({ id: plugin.id });
    30  
    31      assert.equal(Layout.breadcrumbFor('csi.index').text, 'Storage');
    32      assert.equal(Layout.breadcrumbFor('csi.plugins').text, 'Plugins');
    33      assert.equal(Layout.breadcrumbFor('csi.plugins.plugin').text, plugin.id);
    34    });
    35  
    36    test('/csi/plugins/:id should show the plugin name in the title', async function (assert) {
    37      await PluginDetail.visit({ id: plugin.id });
    38  
    39      assert.equal(document.title, `CSI Plugin ${plugin.id} - Nomad`);
    40      assert.equal(PluginDetail.title, plugin.id);
    41    });
    42  
    43    test('/csi/plugins/:id should list additional details for the plugin below the title', async function (assert) {
    44      await PluginDetail.visit({ id: plugin.id });
    45  
    46      assert.ok(
    47        PluginDetail.controllerHealth.includes(
    48          `${Math.round(
    49            (plugin.controllersHealthy / plugin.controllersExpected) * 100
    50          )}%`
    51        )
    52      );
    53      assert.ok(
    54        PluginDetail.controllerHealth.includes(
    55          `${plugin.controllersHealthy}/${plugin.controllersExpected}`
    56        )
    57      );
    58      assert.ok(
    59        PluginDetail.nodeHealth.includes(
    60          `${Math.round((plugin.nodesHealthy / plugin.nodesExpected) * 100)}%`
    61        )
    62      );
    63      assert.ok(
    64        PluginDetail.nodeHealth.includes(
    65          `${plugin.nodesHealthy}/${plugin.nodesExpected}`
    66        )
    67      );
    68      assert.ok(PluginDetail.provider.includes(plugin.provider));
    69    });
    70  
    71    test('/csi/plugins/:id should list all the controller plugin allocations for the plugin', async function (assert) {
    72      await PluginDetail.visit({ id: plugin.id });
    73  
    74      assert.equal(
    75        PluginDetail.controllerAllocations.length,
    76        plugin.controllers.length
    77      );
    78      plugin.controllers.models
    79        .sortBy('updateTime')
    80        .reverse()
    81        .forEach((allocation, idx) => {
    82          assert.equal(
    83            PluginDetail.controllerAllocations.objectAt(idx).id,
    84            allocation.allocID
    85          );
    86        });
    87    });
    88  
    89    test('/csi/plugins/:id should list all the node plugin allocations for the plugin', async function (assert) {
    90      await PluginDetail.visit({ id: plugin.id });
    91  
    92      assert.equal(PluginDetail.nodeAllocations.length, plugin.nodes.length);
    93      plugin.nodes.models
    94        .sortBy('updateTime')
    95        .reverse()
    96        .forEach((allocation, idx) => {
    97          assert.equal(
    98            PluginDetail.nodeAllocations.objectAt(idx).id,
    99            allocation.allocID
   100          );
   101        });
   102    });
   103  
   104    test('each allocation should have high-level details for the allocation', async function (assert) {
   105      const controller = plugin.controllers.models
   106        .sortBy('updateTime')
   107        .reverse()[0];
   108      const allocation = server.db.allocations.find(controller.allocID);
   109      const allocStats = server.db.clientAllocationStats.find(allocation.id);
   110      const taskGroup = server.db.taskGroups.findBy({
   111        name: allocation.taskGroup,
   112        jobId: allocation.jobId,
   113      });
   114  
   115      const tasks = taskGroup.taskIds.map((id) => server.db.tasks.find(id));
   116      const cpuUsed = tasks.reduce((sum, task) => sum + task.resources.CPU, 0);
   117      const memoryUsed = tasks.reduce(
   118        (sum, task) => sum + task.resources.MemoryMB,
   119        0
   120      );
   121  
   122      await PluginDetail.visit({ id: plugin.id });
   123  
   124      PluginDetail.controllerAllocations.objectAt(0).as((allocationRow) => {
   125        assert.equal(
   126          allocationRow.shortId,
   127          allocation.id.split('-')[0],
   128          'Allocation short ID'
   129        );
   130        assert.equal(
   131          allocationRow.createTime,
   132          moment(allocation.createTime / 1000000).format('MMM D')
   133        );
   134        assert.equal(
   135          allocationRow.createTooltip,
   136          moment(allocation.createTime / 1000000).format('MMM DD HH:mm:ss ZZ')
   137        );
   138        assert.equal(
   139          allocationRow.modifyTime,
   140          moment(allocation.modifyTime / 1000000).fromNow()
   141        );
   142        assert.equal(
   143          allocationRow.health,
   144          controller.healthy ? 'Healthy' : 'Unhealthy'
   145        );
   146        assert.equal(
   147          allocationRow.client,
   148          server.db.nodes.find(allocation.nodeId).id.split('-')[0],
   149          'Node ID'
   150        );
   151        assert.equal(
   152          allocationRow.clientTooltip.substr(0, 15),
   153          server.db.nodes.find(allocation.nodeId).name.substr(0, 15),
   154          'Node Name'
   155        );
   156        assert.equal(
   157          allocationRow.job,
   158          server.db.jobs.find(allocation.jobId).name,
   159          'Job name'
   160        );
   161        assert.ok(allocationRow.taskGroup, 'Task group name');
   162        assert.ok(allocationRow.jobVersion, 'Job Version');
   163        assert.equal(
   164          allocationRow.cpu,
   165          Math.floor(allocStats.resourceUsage.CpuStats.TotalTicks) / cpuUsed,
   166          'CPU %'
   167        );
   168        const roundedTicks = Math.floor(
   169          allocStats.resourceUsage.CpuStats.TotalTicks
   170        );
   171        assert.equal(
   172          allocationRow.cpuTooltip,
   173          `${formatHertz(roundedTicks, 'MHz')} / ${formatHertz(cpuUsed, 'MHz')}`,
   174          'Detailed CPU information is in a tooltip'
   175        );
   176        assert.equal(
   177          allocationRow.mem,
   178          allocStats.resourceUsage.MemoryStats.RSS / 1024 / 1024 / memoryUsed,
   179          'Memory used'
   180        );
   181        assert.equal(
   182          allocationRow.memTooltip,
   183          `${formatBytes(
   184            allocStats.resourceUsage.MemoryStats.RSS
   185          )} / ${formatBytes(memoryUsed, 'MiB')}`,
   186          'Detailed memory information is in a tooltip'
   187        );
   188      });
   189    });
   190  
   191    test('each allocation should link to the allocation detail page', async function (assert) {
   192      const controller = plugin.controllers.models
   193        .sortBy('updateTime')
   194        .reverse()[0];
   195  
   196      await PluginDetail.visit({ id: plugin.id });
   197      await PluginDetail.controllerAllocations.objectAt(0).visit();
   198  
   199      assert.equal(currentURL(), `/allocations/${controller.allocID}`);
   200    });
   201  
   202    test('when there are no plugin allocations, the tables present empty states', async function (assert) {
   203      const emptyPlugin = server.create('csi-plugin', {
   204        controllerRequired: true,
   205        controllersHealthy: 0,
   206        controllersExpected: 0,
   207        nodesHealthy: 0,
   208        nodesExpected: 0,
   209      });
   210  
   211      await PluginDetail.visit({ id: emptyPlugin.id });
   212  
   213      assert.ok(PluginDetail.controllerTableIsEmpty);
   214      assert.equal(
   215        PluginDetail.controllerEmptyState.headline,
   216        'No Controller Plugin Allocations'
   217      );
   218  
   219      assert.ok(PluginDetail.nodeTableIsEmpty);
   220      assert.equal(
   221        PluginDetail.nodeEmptyState.headline,
   222        'No Node Plugin Allocations'
   223      );
   224    });
   225  
   226    test('when the plugin is node-only, the controller information is omitted', async function (assert) {
   227      const nodeOnlyPlugin = server.create('csi-plugin', {
   228        controllerRequired: false,
   229      });
   230  
   231      await PluginDetail.visit({ id: nodeOnlyPlugin.id });
   232  
   233      assert.notOk(PluginDetail.controllerAvailabilityIsPresent);
   234      assert.ok(PluginDetail.nodeAvailabilityIsPresent);
   235  
   236      assert.notOk(PluginDetail.controllerHealthIsPresent);
   237      assert.notOk(PluginDetail.controllerTableIsPresent);
   238    });
   239  
   240    test('when there are more than 10 controller or node allocations, only 10 are shown', async function (assert) {
   241      const manyAllocationsPlugin = server.create('csi-plugin', {
   242        shallow: true,
   243        controllerRequired: false,
   244        nodesExpected: 15,
   245      });
   246  
   247      await PluginDetail.visit({ id: manyAllocationsPlugin.id });
   248  
   249      assert.equal(PluginDetail.nodeAllocations.length, 10);
   250    });
   251  
   252    test('the View All links under each allocation table link to a filtered view of the plugins allocation list', async function (assert) {
   253      const serialize = (arr) => window.encodeURIComponent(JSON.stringify(arr));
   254  
   255      await PluginDetail.visit({ id: plugin.id });
   256      assert.ok(
   257        PluginDetail.goToControllerAllocationsText.includes(
   258          plugin.controllers.models.length
   259        )
   260      );
   261      await PluginDetail.goToControllerAllocations();
   262      assert.equal(
   263        currentURL(),
   264        `/csi/plugins/${plugin.id}/allocations?type=${serialize(['controller'])}`
   265      );
   266  
   267      await PluginDetail.visit({ id: plugin.id });
   268      assert.ok(
   269        PluginDetail.goToNodeAllocationsText.includes(plugin.nodes.models.length)
   270      );
   271      await PluginDetail.goToNodeAllocations();
   272      assert.equal(
   273        currentURL(),
   274        `/csi/plugins/${plugin.id}/allocations?type=${serialize(['node'])}`
   275      );
   276    });
   277  });