github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/ui/tests/unit/services/stats-trackers-registry-test.js (about)

     1  import EmberObject from '@ember/object';
     2  import Service from '@ember/service';
     3  import { module, test } from 'qunit';
     4  import { setupTest } from 'ember-qunit';
     5  import { settled } from '@ember/test-helpers';
     6  import Pretender from 'pretender';
     7  import sinon from 'sinon';
     8  import fetch from 'nomad-ui/utils/fetch';
     9  import NodeStatsTracker from 'nomad-ui/utils/classes/node-stats-tracker';
    10  
    11  module('Unit | Service | Stats Trackers Registry', function(hooks) {
    12    setupTest(hooks);
    13  
    14    hooks.beforeEach(function() {
    15      this.subject = function() {
    16        return this.owner.factoryFor('service:stats-trackers-registry').create();
    17      };
    18    });
    19  
    20    hooks.beforeEach(function() {
    21      // Inject a mock token service
    22      const authorizedRequestSpy = (this.tokenAuthorizedRequestSpy = sinon.spy());
    23      const mockToken = Service.extend({
    24        authorizedRequest(url) {
    25          authorizedRequestSpy(url);
    26          return fetch(url);
    27        },
    28      });
    29  
    30      this.owner.register('service:token', mockToken);
    31      this.token = this.owner.lookup('service:token');
    32      this.server = new Pretender(function() {
    33        this.get('/v1/client/stats', () => [
    34          200,
    35          {},
    36          JSON.stringify({
    37            Timestamp: 1234567890,
    38            CPUTicksConsumed: 11,
    39            Memory: {
    40              Used: 12,
    41            },
    42          }),
    43        ]);
    44      });
    45    });
    46  
    47    hooks.afterEach(function() {
    48      this.server.shutdown();
    49    });
    50  
    51    const makeModelMock = (modelName, defaults) => {
    52      const Class = EmberObject.extend(defaults);
    53      Class.prototype.constructor.modelName = modelName;
    54      return Class;
    55    };
    56  
    57    const mockNode = makeModelMock('node', { id: 'test' });
    58  
    59    test('Creates a tracker when one isn’t found', function(assert) {
    60      const registry = this.subject();
    61      const id = 'id';
    62  
    63      assert.equal(registry.get('registryRef').size, 0, 'Nothing in the registry yet');
    64  
    65      const tracker = registry.getTracker(mockNode.create({ id }));
    66      assert.ok(tracker instanceof NodeStatsTracker, 'The correct type of tracker is made');
    67      assert.equal(registry.get('registryRef').size, 1, 'The tracker was added to the registry');
    68      assert.deepEqual(
    69        Array.from(registry.get('registryRef').keys()),
    70        [`node:${id}`],
    71        'The object in the registry has the correct key'
    72      );
    73    });
    74  
    75    test('Returns an existing tracker when one is found', function(assert) {
    76      const registry = this.subject();
    77      const node = mockNode.create();
    78  
    79      const tracker1 = registry.getTracker(node);
    80      const tracker2 = registry.getTracker(node);
    81  
    82      assert.equal(tracker1, tracker2, 'Returns an existing tracker for the same resource');
    83      assert.equal(registry.get('registryRef').size, 1, 'Only one tracker in the registry');
    84    });
    85  
    86    test('Registry does not depend on persistent object references', function(assert) {
    87      const registry = this.subject();
    88      const id = 'some-id';
    89  
    90      const node1 = mockNode.create({ id });
    91      const node2 = mockNode.create({ id });
    92  
    93      assert.notEqual(node1, node2, 'Two different resources');
    94      assert.equal(node1.get('id'), node2.get('id'), 'With the same IDs');
    95      assert.equal(
    96        node1.constructor.modelName,
    97        node2.constructor.modelName,
    98        'And the same className'
    99      );
   100  
   101      assert.equal(registry.getTracker(node1), registry.getTracker(node2), 'Return the same tracker');
   102      assert.equal(registry.get('registryRef').size, 1, 'Only one tracker in the registry');
   103    });
   104  
   105    test('Has a max size', function(assert) {
   106      const registry = this.subject();
   107      const ref = registry.get('registryRef');
   108  
   109      // Kind of a silly assertion, but the exact limit is arbitrary. Whether it's 10 or 1000
   110      // isn't important as long as there is one.
   111      assert.ok(ref.limit < Infinity, `A limit (${ref.limit}) is set`);
   112    });
   113  
   114    test('Registry re-attaches deleted resources to cached trackers', function(assert) {
   115      const registry = this.subject();
   116      const id = 'some-id';
   117  
   118      const node1 = mockNode.create({ id });
   119      let tracker = registry.getTracker(node1);
   120  
   121      assert.ok(tracker.get('node'), 'The tracker has a node');
   122  
   123      tracker.set('node', null);
   124      assert.notOk(tracker.get('node'), 'The tracker does not have a node');
   125  
   126      tracker = registry.getTracker(node1);
   127      assert.equal(
   128        tracker.get('node'),
   129        node1,
   130        'The node was re-attached to the tracker after calling getTracker again'
   131      );
   132    });
   133  
   134    test('Registry re-attaches destroyed resources to cached trackers', async function(assert) {
   135      const registry = this.subject();
   136      const id = 'some-id';
   137  
   138      const node1 = mockNode.create({ id });
   139      let tracker = registry.getTracker(node1);
   140  
   141      assert.ok(tracker.get('node'), 'The tracker has a node');
   142  
   143      node1.destroy();
   144      await settled();
   145  
   146      assert.ok(tracker.get('node').isDestroyed, 'The tracker node is destroyed');
   147  
   148      const node2 = mockNode.create({ id });
   149      tracker = registry.getTracker(node2);
   150      assert.equal(
   151        tracker.get('node'),
   152        node2,
   153        'Since node1 was destroyed but it matches the tracker of node2, node2 is attached to the tracker'
   154      );
   155    });
   156  
   157    test('Removes least recently used when something needs to be removed', function(assert) {
   158      const registry = this.subject();
   159      const activeNode = mockNode.create({ id: 'active' });
   160      const inactiveNode = mockNode.create({ id: 'inactive' });
   161      const limit = registry.get('registryRef').limit;
   162  
   163      // First put in the two tracked nodes
   164      registry.getTracker(activeNode);
   165      registry.getTracker(inactiveNode);
   166  
   167      for (let i = 0; i < limit; i++) {
   168        // Add a new tracker to the registry
   169        const newNode = mockNode.create({ id: `node-${i}` });
   170        registry.getTracker(newNode);
   171  
   172        // But read the active node tracker to keep it fresh
   173        registry.getTracker(activeNode);
   174      }
   175  
   176      const ref = registry.get('registryRef');
   177      assert.equal(ref.size, ref.limit, 'The limit was reached');
   178  
   179      assert.ok(
   180        ref.get('node:active'),
   181        'The active tracker is still in the registry despite being added first'
   182      );
   183      assert.notOk(
   184        ref.get('node:inactive'),
   185        'The inactive tracker got pushed out due to not being accessed'
   186      );
   187    });
   188  
   189    test('Trackers are created using the token authorizedRequest', function(assert) {
   190      const registry = this.subject();
   191      const node = mockNode.create();
   192  
   193      const tracker = registry.getTracker(node);
   194  
   195      tracker.get('poll').perform();
   196      assert.ok(
   197        this.tokenAuthorizedRequestSpy.calledWith(`/v1/client/stats?node_id=${node.get('id')}`),
   198        'The token service authorizedRequest function was used'
   199      );
   200  
   201      return settled();
   202    });
   203  });