github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/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(
    64        registry.get('registryRef').size,
    65        0,
    66        'Nothing in the registry yet'
    67      );
    68  
    69      const tracker = registry.getTracker(mockNode.create({ id }));
    70      assert.ok(
    71        tracker instanceof NodeStatsTracker,
    72        'The correct type of tracker is made'
    73      );
    74      assert.equal(
    75        registry.get('registryRef').size,
    76        1,
    77        'The tracker was added to the registry'
    78      );
    79      assert.deepEqual(
    80        Array.from(registry.get('registryRef').keys()),
    81        [`node:${id}`],
    82        'The object in the registry has the correct key'
    83      );
    84    });
    85  
    86    test('Returns an existing tracker when one is found', function (assert) {
    87      const registry = this.subject();
    88      const node = mockNode.create();
    89  
    90      const tracker1 = registry.getTracker(node);
    91      const tracker2 = registry.getTracker(node);
    92  
    93      assert.equal(
    94        tracker1,
    95        tracker2,
    96        'Returns an existing tracker for the same resource'
    97      );
    98      assert.equal(
    99        registry.get('registryRef').size,
   100        1,
   101        'Only one tracker in the registry'
   102      );
   103    });
   104  
   105    test('Registry does not depend on persistent object references', function (assert) {
   106      const registry = this.subject();
   107      const id = 'some-id';
   108  
   109      const node1 = mockNode.create({ id });
   110      const node2 = mockNode.create({ id });
   111  
   112      assert.notEqual(node1, node2, 'Two different resources');
   113      assert.equal(node1.get('id'), node2.get('id'), 'With the same IDs');
   114      assert.equal(
   115        node1.constructor.modelName,
   116        node2.constructor.modelName,
   117        'And the same className'
   118      );
   119  
   120      assert.equal(
   121        registry.getTracker(node1),
   122        registry.getTracker(node2),
   123        'Return the same tracker'
   124      );
   125      assert.equal(
   126        registry.get('registryRef').size,
   127        1,
   128        'Only one tracker in the registry'
   129      );
   130    });
   131  
   132    test('Has a max size', function (assert) {
   133      const registry = this.subject();
   134      const ref = registry.get('registryRef');
   135  
   136      // Kind of a silly assertion, but the exact limit is arbitrary. Whether it's 10 or 1000
   137      // isn't important as long as there is one.
   138      assert.ok(ref.limit < Infinity, `A limit (${ref.limit}) is set`);
   139    });
   140  
   141    test('Registry re-attaches deleted resources to cached trackers', function (assert) {
   142      const registry = this.subject();
   143      const id = 'some-id';
   144  
   145      const node1 = mockNode.create({ id });
   146      let tracker = registry.getTracker(node1);
   147  
   148      assert.ok(tracker.get('node'), 'The tracker has a node');
   149  
   150      tracker.set('node', null);
   151      assert.notOk(tracker.get('node'), 'The tracker does not have a node');
   152  
   153      tracker = registry.getTracker(node1);
   154      assert.equal(
   155        tracker.get('node'),
   156        node1,
   157        'The node was re-attached to the tracker after calling getTracker again'
   158      );
   159    });
   160  
   161    test('Registry re-attaches destroyed resources to cached trackers', async function (assert) {
   162      const registry = this.subject();
   163      const id = 'some-id';
   164  
   165      const node1 = mockNode.create({ id });
   166      let tracker = registry.getTracker(node1);
   167  
   168      assert.ok(tracker.get('node'), 'The tracker has a node');
   169  
   170      node1.destroy();
   171      await settled();
   172  
   173      assert.ok(tracker.get('node').isDestroyed, 'The tracker node is destroyed');
   174  
   175      const node2 = mockNode.create({ id });
   176      tracker = registry.getTracker(node2);
   177      assert.equal(
   178        tracker.get('node'),
   179        node2,
   180        'Since node1 was destroyed but it matches the tracker of node2, node2 is attached to the tracker'
   181      );
   182    });
   183  
   184    test('Removes least recently used when something needs to be removed', function (assert) {
   185      const registry = this.subject();
   186      const activeNode = mockNode.create({ id: 'active' });
   187      const inactiveNode = mockNode.create({ id: 'inactive' });
   188      const limit = registry.get('registryRef').limit;
   189  
   190      // First put in the two tracked nodes
   191      registry.getTracker(activeNode);
   192      registry.getTracker(inactiveNode);
   193  
   194      for (let i = 0; i < limit; i++) {
   195        // Add a new tracker to the registry
   196        const newNode = mockNode.create({ id: `node-${i}` });
   197        registry.getTracker(newNode);
   198  
   199        // But read the active node tracker to keep it fresh
   200        registry.getTracker(activeNode);
   201      }
   202  
   203      const ref = registry.get('registryRef');
   204      assert.equal(ref.size, ref.limit, 'The limit was reached');
   205  
   206      assert.ok(
   207        ref.get('node:active'),
   208        'The active tracker is still in the registry despite being added first'
   209      );
   210      assert.notOk(
   211        ref.get('node:inactive'),
   212        'The inactive tracker got pushed out due to not being accessed'
   213      );
   214    });
   215  
   216    test('Trackers are created using the token authorizedRequest', function (assert) {
   217      const registry = this.subject();
   218      const node = mockNode.create();
   219  
   220      const tracker = registry.getTracker(node);
   221  
   222      tracker.get('poll').perform();
   223      assert.ok(
   224        this.tokenAuthorizedRequestSpy.calledWith(
   225          `/v1/client/stats?node_id=${node.get('id')}`
   226        ),
   227        'The token service authorizedRequest function was used'
   228      );
   229  
   230      return settled();
   231    });
   232  });