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  }