Skip to content

Commit

Permalink
[ui] Tests for Sentinel Policies (#22398)
Browse files Browse the repository at this point in the history
* Tests for Sentinel Policies UI

* Further sentinel tests

* job allocations test reinstated
  • Loading branch information
philrenaud committed May 31, 2024
1 parent 2054e87 commit 36c2439
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 21 deletions.
6 changes: 3 additions & 3 deletions ui/app/components/sentinel-policy-editor.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,21 @@
<G.RadioField
@id="advisory"
checked={{eq @policy.enforcementLevel "advisory"}}
data-test-token-type="client"
data-test-enforcement-level="advisory"
as |F|>
<F.Label>Advisory</F.Label>
</G.RadioField>
<G.RadioField
@id="soft-mandatory"
checked={{eq @policy.enforcementLevel "soft-mandatory"}}
data-test-token-type="soft-mandatory"
data-test-enforcement-level="soft-mandatory"
as |F|>
<F.Label>Soft Mandatory</F.Label>
</G.RadioField>
<G.RadioField
@id="hard-mandatory"
checked={{eq @policy.enforcementLevel "hard-mandatory"}}
data-test-token-type="hard-mandatory"
data-test-enforcement-level="hard-mandatory"
as |F|>
<F.Label>Hard Mandatory</F.Label>
</G.RadioField>
Expand Down
10 changes: 6 additions & 4 deletions ui/app/templates/administration/sentinel-policies/gallery.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
<Hds::Form::RadioCard::Group as |G|>
<G.Legend>Select a Template</G.Legend>
{{#each this.templates as |template|}}
<G.RadioCard class="form-container" @layout="fixed" @maxWidth="30%" @checked={{eq template.name
this.selectedTemplate}} id={{template.name}} data-test-template-card={{template.name}} {{on "change"
this.onChange}} as |R|>
<R.Label data-test-template-label>{{template.displayName}}</R.Label>
<G.RadioCard class="form-container" @layout="fixed" @maxWidth="30%"
@checked={{eq template.name this.selectedTemplate}}
id={{template.name}}
{{on "change" this.onChange}}
as |R|>
<R.Label data-test-template-card={{template.name}} data-test-template-label>{{template.displayName}}</R.Label>
<R.Description data-test-template-description>{{template.description}}</R.Description>
</G.RadioCard>
{{/each}}
Expand Down
10 changes: 5 additions & 5 deletions ui/app/templates/administration/sentinel-policies/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SPDX-License-Identifier: BUSL-1.1
label="Create Policy from Template"
}}
>
<Hds::Button @text="Create from Template" @icon="plus" @route="administration.sentinel-policies.gallery" />
<Hds::Button @text="Create from Template" @icon="plus" @route="administration.sentinel-policies.gallery" data-test-create-sentinel-policy-from-template />
</span>
{{else}}
<Hds::Button @text="Create Policy" @icon="plus" disabled data-test-disabled-create-sentinel-policy />
Expand All @@ -44,8 +44,8 @@ SPDX-License-Identifier: BUSL-1.1
<LinkTo data-test-sentinel-policy-name={{B.data.name}} @route="administration.sentinel-policies.policy"
@model={{B.data.name}}>{{B.data.name}}</LinkTo>
</B.Td>
<B.Td>{{B.data.description}}</B.Td>
<B.Td>{{B.data.enforcementLevel}}</B.Td>
<B.Td data-test-sentinel-policy-description>{{B.data.description}}</B.Td>
<B.Td data-test-sentinel-policy-enforcement>{{B.data.enforcementLevel}}</B.Td>
{{#if (can "destroy sentinel-policy")}}
<B.Td>
<TwoStepButton
Expand All @@ -65,8 +65,8 @@ SPDX-License-Identifier: BUSL-1.1
</:body>
</Hds::Table>
{{else}}
<div data-test-empty-jobs-list class="empty-message">
<h3 data-test-empty-jobs-list-headline class="empty-message-headline">
<div data-test-empty-sentinel-policy-list class="empty-message">
<h3 data-test-empty-sentinel-policy-list-headline class="empty-message-headline">
No Sentinel Policies
</h3>
<p class="empty-message-body">
Expand Down
1 change: 1 addition & 0 deletions ui/app/templates/components/global-header.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
data-test-header-gutter-toggle
class="gutter-toggle"
aria-label="menu"
role="img"
onclick={{action this.onHamburgerClick}}
>
<HamburgerMenu />
Expand Down
1 change: 1 addition & 0 deletions ui/app/templates/components/gutter-menu.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
data-test-gutter-gutter-toggle
class="gutter-toggle"
aria-label="menu"
role="img"
onclick={{action this.onHamburgerClick}}
>
<HamburgerMenu />
Expand Down
2 changes: 1 addition & 1 deletion ui/app/utils/classes/abstract-stats-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default Mixin.create({
frameMisses: 0,

handleResponse(frame) {
if (frame.error) {
if (!frame || frame.error) {
this.incrementProperty('frameMisses');
if (this.frameMisses >= this.maxFrameMisses) {
// Missing enough data consecutively is effectively a pause
Expand Down
18 changes: 16 additions & 2 deletions ui/mirage/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -936,18 +936,32 @@ export default function () {
});

this.post('/sentinel/policy/:id', function (schema, req) {
const { Name, Description, Rules } = JSON.parse(req.requestBody);
const { Name, Description, EnforcementLevel, Policy, Scope } = JSON.parse(
req.requestBody
);
return server.create('sentinelPolicy', {
name: Name,
description: Description,
rules: Rules,
enforcementLevel: EnforcementLevel,
policy: Policy,
scope: Scope,
});
});

this.get('/sentinel/policy/:id', function ({ sentinelPolicies }, req) {
return this.serialize(sentinelPolicies.findBy({ name: req.params.id }));
});

this.delete('/sentinel/policy/:id', function (schema, req) {
const { id } = req.params;
server.db.sentinelPolicies.remove(id);
return '';
});

this.put('/sentinel/policy/:id', function (schema, req) {
return new Response(200, {}, {});
});

this.delete('/acl/policy/:id', function (schema, request) {
const { id } = request.params;

Expand Down
27 changes: 27 additions & 0 deletions ui/mirage/factories/sentinel-policy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { Factory } from 'ember-cli-mirage';
import faker from 'nomad-ui/mirage/faker';
import { pickOne } from '../utils';

export default Factory.extend({
id: () =>
`${faker.hacker.verb().replace(/\s/g, '-')}-${faker.random.alphaNumeric(
5
)}`,
name() {
return this.id;
},
description: () =>
faker.random.number(10) >= 2 ? faker.lorem.sentence() : null,

policy: `# This policy will always fail. You can temporarily halt all new job updates using this.
main = rule { false }`,

scope: 'submit-job',
enforcementLevel: pickOne(['advisory', 'soft-mandatory', 'hard-mandatory']),
});
18 changes: 16 additions & 2 deletions ui/mirage/scenarios/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,22 @@ function variableTestCluster(server) {
});
}

function policiesTestCluster(server) {
server.create('feature', { name: 'Sentinel Policies' });
function policiesTestCluster(server, options = { sentinel: false }) {
if (options.sentinel) {
server.create('feature', { name: 'Sentinel Policies' });
server.create('sentinel-policy', {
id: 'policy-1',
name: 'policy-1',
description: 'A sentinel policy generated by Mirage',
enforcementLevel: 'soft-mandatory',
policy:
'import "time"\n\nis_weekday = rule { time.day not in ["friday", "saturday", "sunday"] }\nis_open_hours = rule { time.hour > 8 and time.hour < 16 }\n\nmain = rule { is_open_hours and is_weekday }',
scope: 'submit-job',
});

server.createList('sentinel-policy', 5);
}

faker.seed(1);
createTokens(server);
server.createList('agent', 3, 'withConsulLink', 'withVaultLink');
Expand Down
32 changes: 31 additions & 1 deletion ui/tests/acceptance/access-control-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
*/

import { module, test } from 'qunit';
import { currentURL, triggerKeyEvent } from '@ember/test-helpers';
import { currentURL, triggerKeyEvent, click } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import Administration from 'nomad-ui/tests/pages/administration';
import Tokens from 'nomad-ui/tests/pages/settings/tokens';
import { allScenarios } from '../../mirage/scenarios/default';
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
import percySnapshot from '@percy/ember';

// Several related tests within Access Control are contained in the Tokens, Roles,
// and Policies acceptance tests.
Expand Down Expand Up @@ -71,6 +72,35 @@ module('Acceptance | access control', function (hooks) {
);
});

test('Access control does not show Sentinel Policies if they are not present in license', async function (assert) {
allScenarios.policiesTestCluster(server);
await Tokens.visit();
const managementToken = server.db.tokens.findBy(
(t) => t.type === 'management'
);
const { secretId } = managementToken;
await Tokens.secret(secretId).submit();
await Administration.visit();
assert.dom('[data-test-sentinel-policies-card]').doesNotExist();
});

test('Access control shows Sentinel Policies if they are present in license', async function (assert) {
assert.expect(2);
allScenarios.policiesTestCluster(server, { sentinel: true });
await Tokens.visit();
const managementToken = server.db.tokens.findBy(
(t) => t.type === 'management'
);
const { secretId } = managementToken;
await Tokens.secret(secretId).submit();
await Administration.visit();

assert.dom('[data-test-sentinel-policies-card]').exists();
await percySnapshot(assert);
await click('[data-test-sentinel-policies-card] a');
assert.equal(currentURL(), '/administration/sentinel-policies');
});

test('Access control index content', async function (assert) {
await Tokens.visit();
const managementToken = server.db.tokens.findBy(
Expand Down
5 changes: 2 additions & 3 deletions ui/tests/acceptance/job-allocations-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

/* eslint-disable qunit/require-expect */
import { currentURL, click, find } from '@ember/test-helpers';
import { currentURL, click } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
Expand Down Expand Up @@ -85,9 +85,8 @@ module('Acceptance | job allocations', function (hooks) {

await Allocations.visit({ id: job.id });

const firstAllocation = find('[data-test-allocation]');
const firstAllocation = document.querySelector('[data-test-allocation]');
await click(firstAllocation);

const requestToAllocationEndpoint = server.pretender.handledRequests.find(
(request) =>
request.url.includes(
Expand Down
Loading

0 comments on commit 36c2439

Please sign in to comment.