github.com/hernad/nomad@v1.6.112/ui/tests/acceptance/plugin-detail-test.js (about)

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