github.com/hernad/nomad@v1.6.112/ui/tests/integration/components/topo-viz-test.js (about)

     1  /**
     2   * Copyright (c) HashiCorp, Inc.
     3   * SPDX-License-Identifier: MPL-2.0
     4   */
     5  
     6  import { module, test } from 'qunit';
     7  import { render, triggerEvent } from '@ember/test-helpers';
     8  import { setupRenderingTest } from 'ember-qunit';
     9  import hbs from 'htmlbars-inline-precompile';
    10  import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
    11  import { create } from 'ember-cli-page-object';
    12  import { setupMirage } from 'ember-cli-mirage/test-support';
    13  import sinon from 'sinon';
    14  import faker from 'nomad-ui/mirage/faker';
    15  import topoVizPageObject from 'nomad-ui/tests/pages/components/topo-viz';
    16  import { HOSTS } from '../../../mirage/common';
    17  
    18  const TopoViz = create(topoVizPageObject());
    19  
    20  const alloc = (nodeId, jobId, taskGroupName, memory, cpu, props = {}) => ({
    21    id: faker.random.uuid(),
    22    taskGroupName,
    23    isScheduled: true,
    24    allocatedResources: {
    25      cpu,
    26      memory,
    27    },
    28    belongsTo: (type) => ({
    29      id: () => (type === 'job' ? jobId : nodeId),
    30    }),
    31    ...props,
    32  });
    33  
    34  const node = (datacenter, id, memory, cpu) => ({
    35    datacenter,
    36    id,
    37    name: `nomad@${HOSTS[Math.floor(Math.random() * 10) % HOSTS.length]}`,
    38    resources: { memory, cpu },
    39  });
    40  
    41  module('Integration | Component | TopoViz', function (hooks) {
    42    setupRenderingTest(hooks);
    43    setupMirage(hooks);
    44  
    45    const commonTemplate = hbs`
    46      <TopoViz
    47        @nodes={{this.nodes}}
    48        @allocations={{this.allocations}}
    49        @onAllocationSelect={{this.onAllocationSelect}}
    50        @onNodeSelect={{this.onNodeSelect}}
    51        @onDataError={{this.onDataError}} />
    52    `;
    53  
    54    test('presents as a FlexMasonry of datacenters', async function (assert) {
    55      assert.expect(6);
    56  
    57      this.setProperties({
    58        nodes: [node('dc1', 'node0', 1000, 500), node('dc2', 'node1', 1000, 500)],
    59  
    60        allocations: [
    61          alloc('node0', 'job1', 'group', 100, 100),
    62          alloc('node0', 'job1', 'group', 100, 100),
    63          alloc('node1', 'job1', 'group', 100, 100),
    64        ],
    65      });
    66  
    67      await render(commonTemplate);
    68  
    69      assert.equal(TopoViz.datacenters.length, 2);
    70      assert.equal(TopoViz.datacenters[0].nodes.length, 1);
    71      assert.equal(TopoViz.datacenters[1].nodes.length, 1);
    72      assert.equal(TopoViz.datacenters[0].nodes[0].memoryRects.length, 2);
    73      assert.equal(TopoViz.datacenters[1].nodes[0].memoryRects.length, 1);
    74  
    75      await componentA11yAudit(this.element, assert);
    76    });
    77  
    78    test('clicking on a node in a deeply nested TopoViz::Node will toggle node selection and call @onNodeSelect', async function (assert) {
    79      this.setProperties({
    80        // TopoViz must be dense for node selection to be a feature
    81        nodes: Array(55)
    82          .fill(null)
    83          .map((_, index) => node('dc1', `node${index}`, 1000, 500)),
    84        allocations: [],
    85        onNodeSelect: sinon.spy(),
    86      });
    87  
    88      await render(commonTemplate);
    89  
    90      await TopoViz.datacenters[0].nodes[0].selectNode();
    91      assert.ok(this.onNodeSelect.calledOnce);
    92      assert.equal(this.onNodeSelect.getCall(0).args[0].node, this.nodes[0]);
    93  
    94      await TopoViz.datacenters[0].nodes[0].selectNode();
    95      assert.ok(this.onNodeSelect.calledTwice);
    96      assert.equal(this.onNodeSelect.getCall(1).args[0], null);
    97    });
    98  
    99    test('clicking on an allocation in a deeply nested TopoViz::Node will update the topology object with selections and call @onAllocationSelect and @onNodeSelect', async function (assert) {
   100      this.setProperties({
   101        nodes: [node('dc1', 'node0', 1000, 500)],
   102        allocations: [alloc('node0', 'job1', 'group', 100, 100)],
   103        onNodeSelect: sinon.spy(),
   104        onAllocationSelect: sinon.spy(),
   105      });
   106  
   107      await render(commonTemplate);
   108  
   109      await TopoViz.datacenters[0].nodes[0].memoryRects[0].select();
   110      assert.ok(this.onAllocationSelect.calledOnce);
   111      assert.equal(
   112        this.onAllocationSelect.getCall(0).args[0],
   113        this.allocations[0]
   114      );
   115      assert.ok(this.onNodeSelect.calledOnce);
   116  
   117      await TopoViz.datacenters[0].nodes[0].memoryRects[0].select();
   118      assert.ok(this.onAllocationSelect.calledTwice);
   119      assert.equal(this.onAllocationSelect.getCall(1).args[0], null);
   120      assert.ok(this.onNodeSelect.calledTwice);
   121      assert.ok(this.onNodeSelect.alwaysCalledWith(null));
   122    });
   123  
   124    test('clicking on an allocation in a deeply nested TopoViz::Node will associate sibling allocations with curves', async function (assert) {
   125      this.setProperties({
   126        nodes: [
   127          node('dc1', 'node0', 1000, 500),
   128          node('dc1', 'node1', 1000, 500),
   129          node('dc1', 'node2', 1000, 500),
   130          node('dc2', 'node3', 1000, 500),
   131          node('dc2', 'node4', 1000, 500),
   132          node('dc2', 'node5', 1000, 500),
   133        ],
   134        allocations: [
   135          alloc('node0', 'job1', 'group', 100, 100),
   136          alloc('node0', 'job1', 'group', 100, 100),
   137          alloc('node1', 'job1', 'group', 100, 100),
   138          alloc('node2', 'job1', 'group', 100, 100),
   139          alloc('node0', 'job1', 'groupTwo', 100, 100),
   140          alloc('node1', 'job2', 'group', 100, 100),
   141          alloc('node2', 'job2', 'groupTwo', 100, 100),
   142        ],
   143        onNodeSelect: sinon.spy(),
   144        onAllocationSelect: sinon.spy(),
   145      });
   146  
   147      const selectedAllocations = this.allocations.filter(
   148        (alloc) =>
   149          alloc.belongsTo('job').id() === 'job1' &&
   150          alloc.taskGroupName === 'group'
   151      );
   152  
   153      await render(commonTemplate);
   154  
   155      assert.notOk(TopoViz.allocationAssociationsArePresent);
   156  
   157      await TopoViz.datacenters[0].nodes[0].memoryRects[0].select();
   158  
   159      assert.ok(TopoViz.allocationAssociationsArePresent);
   160      assert.equal(
   161        TopoViz.allocationAssociations.length,
   162        selectedAllocations.length * 2
   163      );
   164  
   165      // Lines get redrawn when the window resizes; make sure the lines persist.
   166      await triggerEvent(window, 'resize');
   167      assert.equal(
   168        TopoViz.allocationAssociations.length,
   169        selectedAllocations.length * 2
   170      );
   171  
   172      await TopoViz.datacenters[0].nodes[0].memoryRects[0].select();
   173      assert.notOk(TopoViz.allocationAssociationsArePresent);
   174    });
   175  
   176    test('when the count of sibling allocations is high enough relative to the node count, curves are not rendered', async function (assert) {
   177      this.setProperties({
   178        nodes: [node('dc1', 'node0', 1000, 500), node('dc1', 'node1', 1000, 500)],
   179        allocations: [
   180          // There need to be at least 10 sibling allocations to trigger this behavior
   181          alloc('node0', 'job1', 'group', 100, 100),
   182          alloc('node0', 'job1', 'group', 100, 100),
   183          alloc('node0', 'job1', 'group', 100, 100),
   184          alloc('node0', 'job1', 'group', 100, 100),
   185          alloc('node0', 'job1', 'group', 100, 100),
   186          alloc('node0', 'job1', 'group', 100, 100),
   187          alloc('node1', 'job1', 'group', 100, 100),
   188          alloc('node1', 'job1', 'group', 100, 100),
   189          alloc('node1', 'job1', 'group', 100, 100),
   190          alloc('node1', 'job1', 'group', 100, 100),
   191          alloc('node1', 'job1', 'group', 100, 100),
   192          alloc('node1', 'job1', 'group', 100, 100),
   193          alloc('node0', 'job1', 'groupTwo', 100, 100),
   194        ],
   195        onNodeSelect: sinon.spy(),
   196        onAllocationSelect: sinon.spy(),
   197      });
   198  
   199      await render(commonTemplate);
   200      assert.notOk(TopoViz.allocationAssociationsArePresent);
   201  
   202      await TopoViz.datacenters[0].nodes[0].memoryRects[0].select();
   203      assert.equal(TopoViz.allocationAssociations.length, 0);
   204  
   205      // Lines get redrawn when the window resizes; make sure that doesn't make the lines show up again
   206      await triggerEvent(window, 'resize');
   207      assert.equal(TopoViz.allocationAssociations.length, 0);
   208    });
   209  
   210    test('when one or more nodes are missing the resources property, those nodes are filtered out of the topology view and onDataError is called', async function (assert) {
   211      const badNode = node('dc1', 'node0', 1000, 500);
   212      delete badNode.resources;
   213  
   214      this.setProperties({
   215        nodes: [badNode, node('dc1', 'node1', 1000, 500)],
   216        allocations: [
   217          alloc('node0', 'job1', 'group', 100, 100),
   218          alloc('node0', 'job1', 'group', 100, 100),
   219          alloc('node1', 'job1', 'group', 100, 100),
   220          alloc('node1', 'job1', 'group', 100, 100),
   221          alloc('node0', 'job1', 'groupTwo', 100, 100),
   222        ],
   223        onNodeSelect: sinon.spy(),
   224        onAllocationSelect: sinon.spy(),
   225        onDataError: sinon.spy(),
   226      });
   227  
   228      await render(commonTemplate);
   229  
   230      assert.ok(this.onDataError.calledOnce);
   231      assert.deepEqual(this.onDataError.getCall(0).args[0], [
   232        {
   233          type: 'filtered-nodes',
   234          context: [this.nodes[0]],
   235        },
   236      ]);
   237  
   238      assert.equal(TopoViz.datacenters[0].nodes.length, 1);
   239    });
   240  });