Files
threshold-ui/e2e-tests/admin/tests/dynamic-host-catalog-aws.spec.js
T
Michael Li 1cbf3b227e test(e2e): Add additional assertions to UI tests (#2634)
* test(e2e): Address deprecation

* test(e2e): Add additional connection assertions on tests

* CR: Fix flake when waiting for sessions

If no sessions are available and the page needs to reload, we should wait to ensure that the page has loaded before checking what the state of the sessions are

* CR: Address flake in connect methods

Noticed an issue where a session recording was not playable. The theory is that the session didn't last long enough before it was cancelled. This adds a 2 second wait after establishing a connection before continuing.

* CR: Use authenticated state by default

* CR: Update dynamic host catalog assertion

* CR: Simplify host set checks

- Use .all() when looping
- Add check to see if we need to reload the page or not

* CR: Be more specific with locator

Ran into a conflict with the Static/Dynamic host catalog type and the Static/Dynamic credential type.

* CR: Update connection methods to be more resilient

Rather than using a hardcoded sleep, we will now run a command on the target and wait for a specific string to return before continuing.

* CR
2025-01-06 11:40:32 -05:00

237 lines
7.7 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { test } from '../../global-setup.js';
import { expect } from '@playwright/test';
import { nanoid } from 'nanoid';
import * as boundaryCli from '../../helpers/boundary-cli';
import { CredentialStoresPage } from '../pages/credential-stores.js';
import { HostCatalogsPage } from '../pages/host-catalogs.js';
import { OrgsPage } from '../pages/orgs.js';
import { ProjectsPage } from '../pages/projects.js';
import { SessionsPage } from '../pages/sessions.js';
import { TargetsPage } from '../pages/targets.js';
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test.describe('AWS', async () => {
test('Create an AWS Dynamic Host Catalog and set up Host Sets @ce @aws', async ({
page,
baseURL,
adminAuthMethodId,
adminLoginName,
adminPassword,
awsAccessKeyId,
awsHostSetFilter,
awsHostSetIps,
awsRegion,
awsSecretAccessKey,
targetPort,
sshUser,
sshKeyPath,
}) => {
let orgName;
let connect;
try {
const orgsPage = new OrgsPage(page);
orgName = await orgsPage.createOrg();
const projectsPage = new ProjectsPage(page);
const projectName = await projectsPage.createProject();
// Create host catalog
const hostCatalogName = 'Host Catalog ' + nanoid();
await page
.getByRole('navigation', { name: 'Resources' })
.getByRole('link', { name: 'Host Catalogs' })
.click();
await page.getByRole('link', { name: 'New', exact: true }).click();
await page.getByLabel('Name').fill(hostCatalogName);
await page.getByLabel('Description').fill('This is an automated test');
await page
.getByRole('group', { name: 'Type' })
.getByLabel('Dynamic')
.click();
await page
.getByRole('group', { name: 'Provider' })
.getByLabel('AWS')
.click();
await page.getByLabel('AWS Region').fill(awsRegion);
await page.getByLabel('Access Key ID').fill(awsAccessKeyId);
await page.getByLabel('Secret Access Key').fill(awsSecretAccessKey);
await page
.getByLabel('Disable credential rotation')
.click({ force: true });
await page.getByRole('button', { name: 'Save' }).click();
await expect(
page.getByRole('alert').getByText('Success', { exact: true }),
).toBeVisible();
await page.getByRole('button', { name: 'Dismiss' }).click();
await expect(
page
.getByRole('navigation', { name: 'breadcrumbs' })
.getByText(hostCatalogName),
).toBeVisible();
// Create first host set
const hostSetName = 'Host Set ' + nanoid();
await page.getByRole('link', { name: 'Host Sets' }).click();
await page.getByRole('link', { name: 'New', exact: true }).click();
await page.getByLabel('Name (Optional)').fill(hostSetName);
await page.getByLabel('Description').fill('This is an automated test');
await page
.getByRole('group', { name: 'Filter' })
.getByRole('textbox')
.fill(awsHostSetFilter);
await page
.getByRole('group', { name: 'Filter' })
.getByRole('button', { name: 'Add' })
.click();
await page.getByRole('button', { name: 'Save' }).click();
await expect(
page.getByRole('alert').getByText('Success', { exact: true }),
).toBeVisible();
await page.getByRole('button', { name: 'Dismiss' }).click();
await expect(
page
.getByRole('navigation', { name: 'breadcrumbs' })
.getByText(hostSetName),
).toBeVisible();
await page.getByRole('link', { name: 'Hosts' }).click();
await expect(
page
.getByRole('navigation', { name: 'breadcrumbs' })
.getByText('Hosts'),
).toBeVisible();
// Check number of hosts in host set
const expectedHosts = JSON.parse(awsHostSetIps);
await expect(async () => {
const rowCount = await page
.getByRole('table')
.getByRole('row')
.filter({ hasNot: page.getByRole('columnheader') })
.count();
if (rowCount !== expectedHosts.length) {
await page.reload();
await page
.getByRole('navigation', { name: 'breadcrumbs' })
.getByText(hostSetName)
.waitFor();
}
expect(rowCount).toBe(expectedHosts.length);
}).toPass();
// Navigate to each host in the host set
for (const row of await page
.getByRole('table')
.getByRole('rowgroup')
.nth(1)
.getByRole('row')
.all()) {
const host = row.getByRole('link');
let hostName = await host.innerText();
await host.click();
await expect(
page
.getByRole('navigation', { name: 'breadcrumbs' })
.getByText(hostName),
).toBeVisible();
await page
.getByRole('navigation', { name: 'breadcrumbs' })
.getByText(hostSetName)
.click();
await page.getByRole('link', { name: 'Hosts' }).click();
}
// Create a target and add DHC host set as a host source
const targetsPage = new TargetsPage(page);
const targetName = await targetsPage.createTarget(targetPort);
await targetsPage.addHostSourceToTarget(hostSetName);
// Add another host source
const hostCatalogsPage = new HostCatalogsPage(page);
await hostCatalogsPage.createHostCatalog();
const newHostSetName = await hostCatalogsPage.createHostSet();
await page
.getByRole('navigation', { name: 'Resources' })
.getByRole('link', { name: 'Targets' })
.click();
await page.getByRole('link', { name: targetName }).click();
await targetsPage.addHostSourceToTarget(newHostSetName);
// Remove the host source from the target
await page
.getByRole('link', { name: newHostSetName })
.locator('..')
.locator('..')
.getByRole('button', { name: 'Manage' })
.click();
await page.getByRole('button', { name: 'Remove' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(
page.getByRole('alert').getByText('Success', { exact: true }),
).toBeVisible();
await page.getByRole('button', { name: 'Dismiss' }).click();
// Set up target credentials
const credentialStoresPage = new CredentialStoresPage(page);
await credentialStoresPage.createStaticCredentialStore();
const credentialName =
await credentialStoresPage.createStaticCredentialKeyPair(
sshUser,
sshKeyPath,
);
await targetsPage.addBrokeredCredentialsToTarget(
targetName,
credentialName,
);
// Connect to target
await boundaryCli.authenticateBoundary(
baseURL,
adminAuthMethodId,
adminLoginName,
adminPassword,
);
const orgId = await boundaryCli.getOrgIdFromName(orgName);
const projectId = await boundaryCli.getProjectIdFromName(
orgId,
projectName,
);
const targetId = await boundaryCli.getTargetIdFromName(
projectId,
targetName,
);
connect = await boundaryCli.connectSshToTarget(targetId);
const sessionsPage = new SessionsPage(page);
await sessionsPage.waitForSessionToBeVisible(targetName);
} finally {
if (connect) {
connect.kill('SIGTERM');
}
await boundaryCli.authenticateBoundary(
baseURL,
adminAuthMethodId,
adminLoginName,
adminPassword,
);
if (orgName) {
const orgId = await boundaryCli.getOrgIdFromName(orgName);
if (orgId) {
await boundaryCli.deleteScope(orgId);
}
}
}
});
});