vault/ui/tests/integration/components/enable-replication-form-test.js
Angel Garbarino d3a604b3bc
Continued work on standardizing button selectors (#30972)
* download-button

* remaining data-test-button-

* manual cherry pick

* more

* fix test
2025-06-13 18:47:58 -06:00

307 lines
12 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import sinon from 'sinon';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'vault/tests/helpers';
import { setupEngine } from 'ember-engines/test-support';
import { render, fillIn, click, settled } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { overrideResponse } from 'vault/tests/helpers/stubs';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
const ENABLE_FORM = {
clusterMode: '[data-test-replication-cluster-mode-select]',
clusterAddr: '[data-test-input="primary_cluster_addr"]',
secondaryToken: '[data-test-textarea="secondary-token"]',
primaryAddr: '[data-test-input="primary_api_addr"]',
caFile: '[data-test-input="ca_file"]',
caPath: '[data-test-input="ca_path"]',
notAllowed: '[data-test-not-allowed]',
inlineMessage: '[data-test-inline-error-message]',
cannotEnable: '[data-test-disable-to-continue]',
cannotEnableExplanation: '[data-test-disable-explanation]',
error: '[data-test-message-error-description]',
};
module('Integration | Component | enable-replication-form', function (hooks) {
setupRenderingTest(hooks);
setupMirage(hooks);
setupEngine(hooks, 'replication');
hooks.beforeEach(function () {
this.context = { owner: this.engine };
this.version = this.owner.lookup('service:version');
});
['performance', 'dr'].forEach((replicationMode) => {
test(`it renders correct form inputs when ${replicationMode} replication mode`, async function (assert) {
assert.expect(10);
this.version.features = ['Performance Replication', 'DR Replication'];
this.set('replicationMode', replicationMode);
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode="disabled"
/>`,
this.context
);
assert.dom(ENABLE_FORM.clusterMode).hasValue('primary');
['clusterAddr'].forEach((field) => {
assert.dom(ENABLE_FORM[field]).hasNoValue();
});
assert.dom(GENERAL.submitButton).isNotDisabled();
await fillIn(ENABLE_FORM.clusterMode, 'secondary');
assert.dom(ENABLE_FORM.inlineMessage).hasText('This will immediately clear all data in this cluster!');
['secondaryToken', 'primaryAddr', 'caFile', 'caPath'].forEach((field) => {
assert.dom(ENABLE_FORM[field]).hasNoValue();
});
assert.dom(GENERAL.submitButton).isDisabled();
await fillIn(ENABLE_FORM.secondaryToken, 'some-token');
await fillIn(ENABLE_FORM.primaryAddr, 'some-addr');
assert.dom(GENERAL.submitButton).isNotDisabled();
});
test(`it shows warning when capabilities restricted for ${replicationMode} replication mode`, async function (assert) {
assert.expect(10);
this.version.features = ['Performance Replication', 'DR Replication'];
this.set('replicationMode', replicationMode);
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{false}}
@canEnableSecondary={{false}}
@performanceMode="disabled"
/>`,
this.context
);
assert.dom(ENABLE_FORM.clusterMode).hasValue('primary');
assert
.dom(ENABLE_FORM.notAllowed)
.hasText('The token you are using is not authorized to enable primary replication.');
['clusterAddr'].forEach((field) => {
assert
.dom(ENABLE_FORM[field])
.doesNotExist(`${field}: field does not exist on primary form when not allowed`);
});
assert
.dom(GENERAL.submitButton)
.doesNotExist('on a primary the submit button does not exist when not allowed');
await fillIn(ENABLE_FORM.clusterMode, 'secondary');
assert
.dom(ENABLE_FORM.notAllowed)
.hasText('The token you are using is not authorized to enable secondary replication.');
['secondaryToken', 'primaryAddr', 'caFile', 'caPath'].forEach((field) => {
assert.dom(ENABLE_FORM[field]).doesNotExist();
});
assert
.dom(GENERAL.submitButton)
.doesNotExist('on a secondary the submit button does not exist when not allowed');
});
});
test('enable DR when cluster is perf primary', async function (assert) {
this.version.features = ['Performance Replication', 'DR Replication'];
this.set('replicationMode', 'dr');
this.set('performanceMode', 'primary');
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode={{this.performanceMode}}
/>`,
this.context
);
assert.dom(ENABLE_FORM.clusterMode).hasValue('primary');
['clusterAddr'].forEach((field) => {
assert.dom(ENABLE_FORM[field]).hasNoValue();
});
assert.dom(GENERAL.submitButton).isNotDisabled();
await fillIn(ENABLE_FORM.clusterMode, 'secondary');
assert
.dom(ENABLE_FORM.cannotEnable)
.hasText('Disable Performance Replication in order to enable this cluster as a DR secondary.');
await click(ENABLE_FORM.cannotEnable);
assert
.dom(ENABLE_FORM.cannotEnableExplanation)
.hasText(
"When running as a DR Secondary Vault is read only. For this reason, we don't allow other Replication modes to operate at the same time. This cluster is also currently operating as a Performance Primary."
);
assert.dom(GENERAL.submitButton).isDisabled();
this.set('performanceMode', 'secondary');
await settled();
assert
.dom(ENABLE_FORM.cannotEnableExplanation)
.hasText(
"When running as a DR Secondary Vault is read only. For this reason, we don't allow other Replication modes to operate at the same time. This cluster is also currently operating as a Performance Secondary."
);
});
module('only DR replication in features', function (hooks) {
hooks.beforeEach(function () {
this.version.features = ['DR Replication'];
});
test('attempting to enable performance replication', async function (assert) {
await render(
hbs`<EnableReplicationForm
@replicationMode="performance"
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode="disabled"
/>`,
this.context
);
assert.dom(GENERAL.submitButton).isDisabled();
});
});
module('successful enable', function (hooks) {
hooks.beforeEach(function () {
this.version.features = ['Performance Replication', 'DR Replication'];
this.successSpy = sinon.spy();
this.set('onSuccess', this.successSpy);
});
['dr', 'performance'].forEach((replicationMode) => {
test(`${replicationMode} primary`, async function (assert) {
assert.expect(4);
this.set('replicationMode', replicationMode);
this.server.post(`/sys/replication/${replicationMode}/primary/enable`, (_, req) => {
const body = JSON.parse(req.requestBody);
assert.deepEqual(body, {
primary_cluster_addr: 'some-addr',
});
return {
returned: 'value',
};
});
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode="disabled"
@onSuccess={{this.onSuccess}}
@doTransition={{false}}
/>`,
this.context
);
await fillIn(ENABLE_FORM.clusterAddr, 'some-addr');
await click(GENERAL.submitButton);
// after success
assert.dom(ENABLE_FORM.clusterAddr).hasNoValue();
assert.true(this.successSpy.calledOnce, 'called once');
assert.deepEqual(
this.successSpy.getCall(0).args,
[{ returned: 'value' }, replicationMode, 'primary', false],
'called with correct args'
);
});
test(`${replicationMode} secondary`, async function (assert) {
assert.expect(5);
this.set('replicationMode', replicationMode);
this.server.post(`/sys/replication/${replicationMode}/secondary/enable`, (_, req) => {
const body = JSON.parse(req.requestBody);
assert.deepEqual(
body,
{
primary_api_addr: 'http://127.0.0.1:8200',
token: 'some-token-value',
},
'does not include empty values'
);
return {
returned: 'value',
};
});
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode="disabled"
@onSuccess={{this.onSuccess}}
@doTransition={{true}}
/>`,
this.context
);
await fillIn(ENABLE_FORM.clusterMode, 'secondary');
await fillIn(ENABLE_FORM.secondaryToken, 'some-token-value');
await fillIn(ENABLE_FORM.primaryAddr, 'http://127.0.0.1:8200');
// Fill in then clear ca path
await fillIn(ENABLE_FORM.caPath, 'some-path');
await fillIn(ENABLE_FORM.caPath, '');
await click(GENERAL.submitButton);
// after success
assert.dom(ENABLE_FORM.secondaryToken).hasValue('');
assert.dom(ENABLE_FORM.primaryAddr).hasNoValue();
assert.true(this.successSpy.calledOnce, 'called once');
assert.deepEqual(
this.successSpy.getCall(0).args,
[{ returned: 'value' }, replicationMode, 'secondary', true],
'called with correct args'
);
});
});
});
module('shows API errors', function (hooks) {
hooks.beforeEach(function () {
this.version.features = ['Performance Replication', 'DR Replication'];
this.successSpy = sinon.spy();
this.set('onSuccess', this.successSpy);
});
['dr', 'performance'].forEach((replicationMode) => {
test(`${replicationMode} primary`, async function (assert) {
this.set('replicationMode', replicationMode);
this.server.post(`/sys/replication/${replicationMode}/primary/enable`, overrideResponse(403));
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode="disabled"
@onSuccess={{this.onSuccess}}
/>`,
this.context
);
await fillIn(ENABLE_FORM.clusterAddr, 'some-addr');
await click(GENERAL.submitButton);
assert.dom(ENABLE_FORM.error).hasText('permission denied', 'shows error returned from API');
assert.dom(ENABLE_FORM.clusterAddr).hasValue('some-addr', 'does not clear form');
assert.false(this.successSpy.calledOnce, 'success spy not called');
});
test(`${replicationMode} secondary`, async function (assert) {
this.set('replicationMode', replicationMode);
this.server.post(`/sys/replication/${replicationMode}/secondary/enable`, overrideResponse(403));
await render(
hbs`<EnableReplicationForm
@replicationMode={{this.replicationMode}}
@canEnablePrimary={{true}}
@canEnableSecondary={{true}}
@performanceMode="disabled"
@onSuccess={{this.onSuccess}}
/>`,
this.context
);
await fillIn(ENABLE_FORM.clusterMode, 'secondary');
await fillIn(ENABLE_FORM.secondaryToken, 'some-token-value');
await fillIn(ENABLE_FORM.primaryAddr, 'http://127.0.0.1:8200');
await click(GENERAL.submitButton);
// after error
assert.dom(ENABLE_FORM.error).hasText('permission denied', 'shows error returned from API');
assert.dom(ENABLE_FORM.secondaryToken).hasValue('some-token-value', 'does not clear form');
assert.false(this.successSpy.calledOnce, 'success spy not called');
});
});
});
});