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 });