open-nomad/ui/tests/unit/models/job-test.js
Jai 08d97a19ca
feat: visualize HCL Job Specification in the Nomad UI jobs.job.definition view (#16669)
* ui:  Toggle for `read-only` view (#16279)

* ui: model update for specification

* style: add styling for select

* style: add styling for select

* refact: add spec to view

* refact: update component API

* test: refactor for new UI state

* refact: clean conditional

* refact: update component API for prop

* chore: correct naming

* chore:  remove `fn` helper

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>

* update `default` Mirage scenario (#16496)

* chore: update mirage scenario:

* ui: conditionally render toggle button (#16497)

* chore: update css variable name (#16498)

---------

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>

* ui:  Display JSON view of variables associated to job specification (#16570)

* chore: move fixture to util

* chore: update tests:

* ui: display variables table

* chore: add mirage fixture (#16572)

* ui: regex for job spec parse (#16668)

* ui: remove variable table (#16670)

* ui:  notify user if specification has variables (#16671)

* ui: regex for job spec parse

* chore: deprecate variable references

* chore: update mirage

* ui: add notification

* test: add test coverage for parse method (#16590)

* refact: `JobEditor` reactive query parameters (#16710)

* refact: add query parameter

* refact: move toggle action to controller

* ui:  remove toggle behavior in `JobEditor` (#16711)

* refact: rename logic for select

* chore: instantiate qp in route

* refact:  uniform alerts (#16715)

* style: buffer between alert and header

* refact: extract alerts into a component

* chore: update tests for qp

* chore: defensive logic for app controller

* refact:  move `edit` state to controller (#16725)

* refact: move edit state to controller

* refact: handle edit state (#16731)

* refact: handle edit state

* ui:  warning message (#16732)

* ui: warning message

* ui:  enable editing of HCL vars in the UI (#16734)

* enable editing of HCL vars

* refact: default qp logic

* refact: alert condition

* refact: Pass `variables` as string (#16849)

* ui:  Toggle for `read-only` view (#16279)

* ui: model update for specification

* style: add styling for select

* style: add styling for select

* refact: add spec to view

* refact: update component API

* test: refactor for new UI state

* refact: clean conditional

* refact: update component API for prop

* chore: correct naming

* chore:  remove `fn` helper

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>

* update `default` Mirage scenario (#16496)

* chore: update mirage scenario:

* ui: conditionally render toggle button (#16497)

* chore: update css variable name (#16498)

---------

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>

* refact: `JobEditor` reactive query parameters (#16710)

* refact: add query parameter

* refact: move toggle action to controller

* ui:  remove toggle behavior in `JobEditor` (#16711)

* refact: rename logic for select

* chore: instantiate qp in route

* refact:  uniform alerts (#16715)

* style: buffer between alert and header

* refact: extract alerts into a component

* chore: update tests for qp

* chore: defensive logic for app controller

* refact:  move `edit` state to controller (#16725)

* refact: move edit state to controller

* refact: handle edit state (#16731)

* refact: handle edit state

* ui:  warning message (#16732)

* ui: warning message

* ui:  enable editing of HCL vars in the UI (#16734)

* enable editing of HCL vars

* refact: default qp logic

* refact: alert condition

* refact: variables as string

* style: revert styling change

---------

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>

* bug: correctly edit variables (#16989)

* ui: visualize variables (#16987)

* ui: fetchRawSpecification

* refact: integrate new model method

* test: fetchRaw unit

* styling: enable height on cm

* chore: update copy

* feat: visual variables

* chore: conditional render info txt

* refact: add mirage endpoint

* refact: update test for new schema

* refact: job submit flow (#17015)

* refact: job update logic

* chore: remove dead code

* bug:  update `job.run` and `job.update` adapter methods (#17055)

* refact:  update adapter

* chore: update api usage

* styling:  UX requests (#17064)

* refact:  update adapter

* chore: update api usage

* styling: disable toggle w text

* styling: stick button

* style: space out alerts

* chore:  autofocus on first editor

* bug: dismiss alert

* chore:  add jsdoc and assertion check

* chore:  update mirage for Vercel (#17054)

* chore: mirage logic for vercel deploy

* chore:  update test for mirage change

* refact:  API refactoring (#17083)

* refact: udpate for req schema

* refact: update for variable flags and literal

* bug: visualize job model not derived state

* chore:  update copy

* chore: fix incorrect copy

* chore: deprecate variables derived state

* chore: update copy

* feat: enable toggle on edit

* chore: prettify

* refact: move conditional

---------

Co-authored-by: Phil Renaud <phil.renaud@hashicorp.com>
2023-05-09 11:03:52 -04:00

191 lines
4.9 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import sinon from 'sinon';
module('Unit | Model | job', function (hooks) {
setupTest(hooks);
test('should expose aggregate allocations derived from task groups', function (assert) {
const store = this.owner.lookup('service:store');
let summary;
run(() => {
summary = store.createRecord('job-summary', {
taskGroupSummaries: [
{
name: 'one',
queuedAllocs: 1,
startingAllocs: 2,
runningAllocs: 3,
completeAllocs: 4,
failedAllocs: 5,
lostAllocs: 6,
unknownAllocs: 7,
},
{
name: 'two',
queuedAllocs: 2,
startingAllocs: 4,
runningAllocs: 6,
completeAllocs: 8,
failedAllocs: 10,
lostAllocs: 12,
unknownAllocs: 14,
},
{
name: 'three',
queuedAllocs: 3,
startingAllocs: 6,
runningAllocs: 9,
completeAllocs: 12,
failedAllocs: 15,
lostAllocs: 18,
unknownAllocs: 21,
},
],
});
});
const job = run(() =>
this.owner.lookup('service:store').createRecord('job', {
summary,
name: 'example',
taskGroups: [
{
name: 'one',
count: 0,
tasks: [],
},
{
name: 'two',
count: 0,
tasks: [],
},
{
name: 'three',
count: 0,
tasks: [],
},
],
})
);
assert.equal(
job.get('totalAllocs'),
job
.get('taskGroups')
.mapBy('summary.totalAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'totalAllocs is the sum of all group totalAllocs'
);
assert.equal(
job.get('queuedAllocs'),
job
.get('taskGroups')
.mapBy('summary.queuedAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'queuedAllocs is the sum of all group queuedAllocs'
);
assert.equal(
job.get('startingAllocs'),
job
.get('taskGroups')
.mapBy('summary.startingAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'startingAllocs is the sum of all group startingAllocs'
);
assert.equal(
job.get('runningAllocs'),
job
.get('taskGroups')
.mapBy('summary.runningAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'runningAllocs is the sum of all group runningAllocs'
);
assert.equal(
job.get('completeAllocs'),
job
.get('taskGroups')
.mapBy('summary.completeAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'completeAllocs is the sum of all group completeAllocs'
);
assert.equal(
job.get('failedAllocs'),
job
.get('taskGroups')
.mapBy('summary.failedAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'failedAllocs is the sum of all group failedAllocs'
);
assert.equal(
job.get('lostAllocs'),
job
.get('taskGroups')
.mapBy('summary.lostAllocs')
.reduce((sum, allocs) => sum + allocs, 0),
'lostAllocs is the sum of all group lostAllocs'
);
});
module('#parse', function () {
test('it parses JSON', async function (assert) {
const store = this.owner.lookup('service:store');
const model = store.createRecord('job');
model.set('_newDefinition', '{"name": "Tomster"}');
const setIdByPayloadSpy = sinon.spy(model, 'setIdByPayload');
const result = await model.parse();
assert.deepEqual(
model.get('_newDefinitionJSON'),
{ name: 'Tomster' },
'Sets _newDefinitionJSON correctly'
);
assert.ok(
setIdByPayloadSpy.calledWith({ name: 'Tomster' }),
'setIdByPayload is called with the parsed JSON'
);
assert.deepEqual(result, '{"name": "Tomster"}', 'Returns the JSON input');
});
test('it dispatches a POST request to the /parse endpoint (eagerly assumes HCL specification) if JSON parse method errors', async function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const model = store.createRecord('job');
model.set('_newDefinition', 'invalidJSON');
const adapter = store.adapterFor('job');
adapter.parse = sinon.stub().resolves('invalidJSON');
await model.parse();
assert.ok(
adapter.parse.calledWith('invalidJSON', undefined),
'adapter parse method should be called'
);
assert.deepEqual(
model.get('_newDefinitionJSON'),
'invalidJSON',
'_newDefinitionJSON is set'
);
});
});
});