github.com/hernad/nomad@v1.6.112/ui/tests/unit/adapters/node-test.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 import { run } from '@ember/runloop'; 7 import { module, test } from 'qunit'; 8 import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage'; 9 import { setupTest } from 'ember-qunit'; 10 import { settled } from '@ember/test-helpers'; 11 12 module('Unit | Adapter | Node', function (hooks) { 13 setupTest(hooks); 14 15 hooks.beforeEach(function () { 16 this.store = this.owner.lookup('service:store'); 17 this.subject = () => this.store.adapterFor('node'); 18 19 window.localStorage.clear(); 20 21 this.server = startMirage(); 22 23 this.server.create('region', { id: 'region-1' }); 24 this.server.create('region', { id: 'region-2' }); 25 26 this.server.create('node-pool'); 27 this.server.create('node', { id: 'node-1' }); 28 this.server.create('node', { id: 'node-2' }); 29 this.server.create('job', { id: 'job-1', createAllocations: false }); 30 31 this.server.create('allocation', { id: 'node-1-1', nodeId: 'node-1' }); 32 this.server.create('allocation', { id: 'node-1-2', nodeId: 'node-1' }); 33 this.server.create('allocation', { id: 'node-2-1', nodeId: 'node-2' }); 34 this.server.create('allocation', { id: 'node-2-2', nodeId: 'node-2' }); 35 }); 36 37 hooks.afterEach(function () { 38 this.server.shutdown(); 39 }); 40 41 test('findHasMany removes old related models from the store', async function (assert) { 42 // Fetch the model and related allocations 43 let node = await run(() => this.store.findRecord('node', 'node-1')); 44 let allocations = await run(() => findHasMany(node, 'allocations')); 45 assert.equal( 46 allocations.get('length'), 47 this.server.db.allocations.where({ nodeId: node.get('id') }).length, 48 'Allocations returned from the findHasMany matches the db state' 49 ); 50 51 await settled(); 52 server.db.allocations.remove('node-1-1'); 53 54 allocations = await run(() => findHasMany(node, 'allocations')); 55 const dbAllocations = this.server.db.allocations.where({ 56 nodeId: node.get('id'), 57 }); 58 assert.equal( 59 allocations.get('length'), 60 dbAllocations.length, 61 'Allocations returned from the findHasMany matches the db state' 62 ); 63 assert.equal( 64 this.store.peekAll('allocation').get('length'), 65 dbAllocations.length, 66 'Server-side deleted allocation was removed from the store' 67 ); 68 }); 69 70 test('findHasMany does not remove old unrelated models from the store', async function (assert) { 71 // Fetch the first node and related allocations 72 const node = await run(() => this.store.findRecord('node', 'node-1')); 73 await run(() => findHasMany(node, 'allocations')); 74 75 // Also fetch the second node and related allocations; 76 const node2 = await run(() => this.store.findRecord('node', 'node-2')); 77 await run(() => findHasMany(node2, 'allocations')); 78 79 await settled(); 80 assert.deepEqual( 81 this.store.peekAll('allocation').mapBy('id').sort(), 82 ['node-1-1', 'node-1-2', 'node-2-1', 'node-2-2'], 83 'All allocations for the first and second node are in the store' 84 ); 85 86 server.db.allocations.remove('node-1-1'); 87 88 // Reload the related allocations now that one was removed server-side 89 await run(() => findHasMany(node, 'allocations')); 90 assert.deepEqual( 91 this.store.peekAll('allocation').mapBy('id').sort(), 92 ['node-1-2', 'node-2-1', 'node-2-2'], 93 'The deleted allocation is removed from the store and the allocations associated with the other node are untouched' 94 ); 95 }); 96 97 const testCases = [ 98 { 99 variation: '', 100 id: 'node-1', 101 region: null, 102 eligibility: 'POST /v1/node/node-1/eligibility', 103 drain: 'POST /v1/node/node-1/drain', 104 }, 105 { 106 variation: 'with non-default region', 107 id: 'node-1', 108 region: 'region-2', 109 eligibility: 'POST /v1/node/node-1/eligibility?region=region-2', 110 drain: 'POST /v1/node/node-1/drain?region=region-2', 111 }, 112 ]; 113 114 testCases.forEach((testCase) => { 115 test(`setEligible makes the correct POST request to /:node_id/eligibility ${testCase.variation}`, async function (assert) { 116 const { pretender } = this.server; 117 if (testCase.region) 118 window.localStorage.nomadActiveRegion = testCase.region; 119 120 const node = await run(() => this.store.findRecord('node', testCase.id)); 121 await this.subject().setEligible(node); 122 123 const request = pretender.handledRequests.lastObject; 124 assert.equal(`${request.method} ${request.url}`, testCase.eligibility); 125 assert.deepEqual(JSON.parse(request.requestBody), { 126 NodeID: node.id, 127 Eligibility: 'eligible', 128 }); 129 }); 130 131 test(`setIneligible makes the correct POST request to /:node_id/eligibility ${testCase.variation}`, async function (assert) { 132 const { pretender } = this.server; 133 if (testCase.region) 134 window.localStorage.nomadActiveRegion = testCase.region; 135 136 const node = await run(() => this.store.findRecord('node', testCase.id)); 137 await this.subject().setIneligible(node); 138 139 const request = pretender.handledRequests.lastObject; 140 assert.equal(`${request.method} ${request.url}`, testCase.eligibility); 141 assert.deepEqual(JSON.parse(request.requestBody), { 142 NodeID: node.id, 143 Eligibility: 'ineligible', 144 }); 145 }); 146 147 test(`drain makes the correct POST request to /:node_id/drain with appropriate defaults ${testCase.variation}`, async function (assert) { 148 const { pretender } = this.server; 149 if (testCase.region) 150 window.localStorage.nomadActiveRegion = testCase.region; 151 152 const node = await run(() => this.store.findRecord('node', testCase.id)); 153 await this.subject().drain(node); 154 155 const request = pretender.handledRequests.lastObject; 156 assert.equal(`${request.method} ${request.url}`, testCase.drain); 157 assert.deepEqual(JSON.parse(request.requestBody), { 158 NodeID: node.id, 159 DrainSpec: { 160 Deadline: 0, 161 IgnoreSystemJobs: true, 162 }, 163 }); 164 }); 165 166 test(`drain makes the correct POST request to /:node_id/drain with the provided drain spec ${testCase.variation}`, async function (assert) { 167 const { pretender } = this.server; 168 if (testCase.region) 169 window.localStorage.nomadActiveRegion = testCase.region; 170 171 const node = await run(() => this.store.findRecord('node', testCase.id)); 172 173 const spec = { Deadline: 123456789, IgnoreSystemJobs: false }; 174 await this.subject().drain(node, spec); 175 176 const request = pretender.handledRequests.lastObject; 177 assert.equal(`${request.method} ${request.url}`, testCase.drain); 178 assert.deepEqual(JSON.parse(request.requestBody), { 179 NodeID: node.id, 180 DrainSpec: { 181 Deadline: spec.Deadline, 182 IgnoreSystemJobs: spec.IgnoreSystemJobs, 183 }, 184 }); 185 }); 186 187 test(`forceDrain makes the correct POST request to /:node_id/drain with appropriate defaults ${testCase.variation}`, async function (assert) { 188 const { pretender } = this.server; 189 if (testCase.region) 190 window.localStorage.nomadActiveRegion = testCase.region; 191 192 const node = await run(() => this.store.findRecord('node', testCase.id)); 193 194 await this.subject().forceDrain(node); 195 196 const request = pretender.handledRequests.lastObject; 197 assert.equal(`${request.method} ${request.url}`, testCase.drain); 198 assert.deepEqual(JSON.parse(request.requestBody), { 199 NodeID: node.id, 200 DrainSpec: { 201 Deadline: -1, 202 IgnoreSystemJobs: true, 203 }, 204 }); 205 }); 206 207 test(`forceDrain makes the correct POST request to /:node_id/drain with the provided drain spec ${testCase.variation}`, async function (assert) { 208 const { pretender } = this.server; 209 if (testCase.region) 210 window.localStorage.nomadActiveRegion = testCase.region; 211 212 const node = await run(() => this.store.findRecord('node', testCase.id)); 213 214 const spec = { Deadline: 123456789, IgnoreSystemJobs: false }; 215 await this.subject().forceDrain(node, spec); 216 217 const request = pretender.handledRequests.lastObject; 218 assert.equal(`${request.method} ${request.url}`, testCase.drain); 219 assert.deepEqual(JSON.parse(request.requestBody), { 220 NodeID: node.id, 221 DrainSpec: { 222 Deadline: -1, 223 IgnoreSystemJobs: spec.IgnoreSystemJobs, 224 }, 225 }); 226 }); 227 228 test(`cancelDrain makes the correct POST request to /:node_id/drain ${testCase.variation}`, async function (assert) { 229 const { pretender } = this.server; 230 if (testCase.region) 231 window.localStorage.nomadActiveRegion = testCase.region; 232 233 const node = await run(() => this.store.findRecord('node', testCase.id)); 234 235 await this.subject().cancelDrain(node); 236 237 const request = pretender.handledRequests.lastObject; 238 assert.equal(`${request.method} ${request.url}`, testCase.drain); 239 assert.deepEqual(JSON.parse(request.requestBody), { 240 NodeID: node.id, 241 DrainSpec: null, 242 }); 243 }); 244 }); 245 }); 246 247 // Using fetchLink on a model's hasMany relationship exercises the adapter's 248 // findHasMany method as well normalizing the response and pushing it to the store 249 function findHasMany(model, relationshipName) { 250 const relationship = model.relationshipFor(relationshipName); 251 return model.hasMany(relationship.key).reload(); 252 }