diff --git a/ui/app/templates/components/placement-failure.hbs b/ui/app/templates/components/placement-failure.hbs new file mode 100644 index 000000000..63f49a826 --- /dev/null +++ b/ui/app/templates/components/placement-failure.hbs @@ -0,0 +1,40 @@ +{{#if taskGroup.placementFailures}} + {{#with taskGroup.placementFailures as |failures|}} +

+ {{taskGroup.name}} + {{inc failures.coalescedFailures}} unplaced +

+ + {{/with}} +{{/if}} + diff --git a/ui/app/templates/jobs/job/index.hbs b/ui/app/templates/jobs/job/index.hbs index 8a0ac1c0d..bc2e6b7ce 100644 --- a/ui/app/templates/jobs/job/index.hbs +++ b/ui/app/templates/jobs/job/index.hbs @@ -56,45 +56,7 @@
{{#each model.taskGroups as |taskGroup|}} - {{#if taskGroup.placementFailures}} - {{#with taskGroup.placementFailures as |failures|}} -

- {{taskGroup.name}} - {{inc failures.coalescedFailures}} unplaced -

- - {{/with}} - {{/if}} + {{placement-failure taskGroup=taskGroup}} {{/each}}
diff --git a/ui/tests/integration/job-diff-test.js b/ui/tests/integration/job-diff-test.js index d1821e452..d311ca4f2 100644 --- a/ui/tests/integration/job-diff-test.js +++ b/ui/tests/integration/job-diff-test.js @@ -1,6 +1,7 @@ import { findAll, find } from 'ember-native-dom-helpers'; import { test, moduleForComponent } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; +import cleanWhitespace from '../utils/clean-whitespace'; moduleForComponent('job-diff', 'Integration | Component | job diff', { integration: true, @@ -192,10 +193,3 @@ function field(name, type, newVal, oldVal) { Name: name, }; } - -function cleanWhitespace(string) { - return string - .replace(/\n/g, '') - .replace(/ +/g, ' ') - .trim(); -} diff --git a/ui/tests/integration/placement-failure-test.js b/ui/tests/integration/placement-failure-test.js new file mode 100644 index 000000000..b43a1b553 --- /dev/null +++ b/ui/tests/integration/placement-failure-test.js @@ -0,0 +1,144 @@ +import { find, findAll } from 'ember-native-dom-helpers'; +import { test, moduleForComponent } from 'ember-qunit'; +import { assign } from '@ember/polyfills'; +import hbs from 'htmlbars-inline-precompile'; +import cleanWhitespace from '../utils/clean-whitespace'; + +moduleForComponent('placement-failure', 'Integration | Component | placement failures', { + integration: true, +}); + +const commonTemplate = hbs` + {{placement-failure taskGroup=taskGroup}} +`; + +test('should render the placement failure (basic render)', function(assert) { + const name = 'Placement Failure'; + const failures = 11; + this.set( + 'taskGroup', + createFixture( + { + coalescedFailures: failures - 1 + }, + name + ) + ); + + this.render(commonTemplate); + + assert.equal( + cleanWhitespace(find('[data-test-placement-failure-task-group]').firstChild.wholeText), + name, + 'Title is rendered with the name of the placement failure' + ); + assert.equal( + parseInt(find('[data-test-placement-failure-coalesced-failures]').textContent), + failures, + 'Title is rendered correctly with a count of unplaced' + ); + assert.equal( + findAll('[data-test-placement-failure-no-evaluated-nodes]').length, + 1, + 'No evaluated nodes message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-no-nodes-available]').length, + 1, + 'No nodes in datacenter message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-class-filtered]').length, + 1, + 'Class filtered message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-constraint-filtered]').length, + 1, + 'Constraint filtered message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-nodes-exhausted]').length, + 1, + 'Node exhausted message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-class-exhausted]').length, + 1, + 'Class exhausted message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-dimension-exhausted]').length, + 1, + 'Dimension exhausted message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-quota-exhausted]').length, + 1, + 'Quota exhausted message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-scores]').length, + 1, + 'Scores message shown' + ); +}); + +test('should render correctly when a node is not evaluated', function(assert) { + this.set( + 'taskGroup', + createFixture( + { + nodesEvaluated: 1, + nodesExhausted: 0 + } + ) + ); + + this.render(commonTemplate); + + assert.equal( + findAll('[data-test-placement-failure-no-evaluated-nodes]').length, + 0, + 'No evaluated nodes message shown' + ); + assert.equal( + findAll('[data-test-placement-failure-nodes-exhausted]').length, + 0, + 'Nodes exhausted message NOT shown when there are no nodes exausted' + ); +}); + +function createFixture(obj = {}, name = 'Placement Failure') { + return { + name: name, + placementFailures: assign({ + coalescedFailures: 10, + nodesEvaluated: 0, + nodesAvailable: { + datacenter: 0, + }, + classFiltered: { + filtered: 1, + }, + constraintFiltered: { + 'prop = val': 1, + }, + nodesExhausted: 3, + classExhausted: { + class: 3, + }, + dimensionExhausted: { + iops: 3, + }, + quotaExhausted: { + quota: 'dimension', + }, + scores: { + name: 3, + }, + }, + obj + ) + }; +} diff --git a/ui/tests/utils/clean-whitespace.js b/ui/tests/utils/clean-whitespace.js new file mode 100644 index 000000000..cc3d5282e --- /dev/null +++ b/ui/tests/utils/clean-whitespace.js @@ -0,0 +1,8 @@ +// cleans whitespace from a string, for example for cleaning +// textContent in DOM nodes with indentation +export default function cleanWhitespace(string) { + return string + .replace(/\n/g, '') + .replace(/ +/g, ' ') + .trim(); +}