Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PMM-12293 re-enabled portal SSO tests #682

Merged
merged 20 commits into from
Sep 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/pmm-ui-tests-matrix.yml
Original file line number Diff line number Diff line change
@@ -9,6 +9,10 @@ on:
description: 'pmm-ui-tests repository branch'
default: 'main'
required: true
pmm_qa_branch:
description: 'pmm-qa repository branch(for setup)'
default: 'main'
required: true
pmm_server_version:
description: 'PMM Server docker image'
default: 'perconalab/pmm-server:dev-latest'
@@ -17,10 +21,6 @@ on:
description: 'PMM Client version to test (dev-latest|pmm2-latest|pmm2-rc|x.xx.x)'
default: 'dev-latest'
required: true
pmm_qa_branch:
description: 'pmm-qa repository branch(for setup)'
default: 'main'
required: true

jobs:
rbac:
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ services:
- PMM_DEBUG=1
- ENABLE_RBAC=1
- PERCONA_TEST_SAAS_HOST=check-dev.percona.com:443
- GF_AUTH_OAUTH_ALLOW_INSECURE_EMAIL_LOOKUP=1
- PERCONA_PORTAL_URL=https://portal-dev.percona.com
- PERCONA_TEST_CHECKS_PUBLIC_KEY=RWTg+ZmCCjt7O8eWeAmTLAqW+1ozUbpRSKSwNTmO+exlS5KEIPYWuYdX
- PERCONA_TEST_PLATFORM_ADDRESS=https://check-dev.percona.com:443
14 changes: 11 additions & 3 deletions playwright-tests/README.md
Original file line number Diff line number Diff line change
@@ -34,12 +34,16 @@ this is it! tests are good to go on specified PMM server.
ex: create `.env` file with the following line `PMM_UI_URL=http://myPmmServer.com`

### Running tests:
Execute command in the **playwright-tests** folder
Execute command in the **playwright-tests** folder

Note! since portal tests require spcial setup, all tests are split
into 2 "projects": Chromium(without setup) and Portal(with setup).
Run tests without project flag or "--project=Chromium" will run portal setup
* run all tests: `npx playwright test`
* run a single test file: `npx playwright test --projet=Cromium rbac.spec.ts`
* run a single test file: `npx playwright test --projet=Cromium access-control.spec.ts`
* run Portal tests: `npx playwright test --projet=Portal -g @portal`
* run a set of test files: `npx playwright test tests/todo-page/ tests/landing-page/`
* run files that have **my-spec** or **my-spec-2** in the file name: `npx playwright test my-spec my-spec-2`
* run files that have **my-spec** or **my-spec-2** in the file name: `npx playwright test --project=Chromium my-spec my-spec-2`
* run desired [groups/tags](https://playwright.dev/docs/test-annotations#tag-tests): `npx playwright test --grep @rbac`

### Test report
@@ -53,6 +57,10 @@ Full list of arguments available on [Playwright docs](https://playwright.dev/doc

`npx playwright test --config=local.config.ts`

`--quiet` Run tests with no console output, ex:

`npx playwright test --project=Chromium --quiet`

`--debug` Run tests with Playwright Inspector, ex:

`npx playwright test --debug`
17 changes: 3 additions & 14 deletions playwright-tests/api/helpers/api-helper.ts
Original file line number Diff line number Diff line change
@@ -16,10 +16,10 @@ const getConfiguredRestApi = async (): Promise<APIRequestContext> => {
};

const apiHelper = {
// TODO: move it from the helper to proper file API? It's not actually API call.
// TODO: remove in favor of xxxPage.network.suppressTour().
confirmTour: async (page: Page) => {
await page.route('**/v1/user', (route) => {
route.fulfill({
await page.route('**/v1/user', async (route) => {
await route.fulfill({
status: 200,
body: JSON.stringify({
user_id: 1,
@@ -30,17 +30,6 @@ const apiHelper = {
});
},

// TODO: move it from the helper to proper file API? It's not actually API call.
async interceptBackEndCall(page: Page, interceptedRoute: string, data = {}) {
await page.route(interceptedRoute, async (route) => {
await route.fulfill({
body: JSON.stringify(data),
contentType: 'application/json',
headers: {},
});
});
},

/**
* Implements HTTP GET to PMM Server API
* Request parameters can be configured with original client options.
11 changes: 6 additions & 5 deletions playwright-tests/api/helpers/portal-api-helper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { APIRequestContext, APIResponse, expect, request } from '@playwright/test';
import {
APIRequestContext, APIResponse, expect, request,
} from '@playwright/test';
import constants from '@helpers/constants';

const checkAndReturnResponse = async (r: APIResponse) => {
await expect(r, `Expected to be OK: ${r.status()} ${r.statusText()}`).toBeOK();
console.log(`Status: ${r.status()} ${r.statusText()}`);
return r.json();
};

@@ -27,16 +30,14 @@ const getRequestContext = async (
): Promise<APIRequestContext> => {
const options: ContextOptions = { baseURL: constants.portal.url, timeout };
if (accessToken) {
options.extraHTTPHeaders = {
Authorization: `Bearer ${accessToken}`,
};
options.extraHTTPHeaders = { Authorization: `Bearer ${accessToken}` };
}
return request.newContext(options);
};

export const portalApiHelper = {
async post(params: RequestParams) {
console.log(`POST: ${constants.portal.url}${params.path}\nPayload: ${JSON.stringify(params.data)}`);
console.log(`POST: ${constants.portal.url}${params.path}`);
return (await getRequestContext(params))
.post(params.path, { data: params.data }).then(checkAndReturnResponse);
},
18 changes: 6 additions & 12 deletions playwright-tests/api/portal.api.ts
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ export const portalApi = {
password,
},
});

return response.access_token as string;
},

@@ -18,39 +19,32 @@ export const portalApi = {
path: '/v1/orgs',
accessToken,
timeout: 120_000,
data: {
name: orgName,
},
data: { name: orgName },
}) as { org: { id: string } };
},

async deleteOrg(accessToken: string, orgId: string) {
return portalApiHelper.delete({
path: `/v1/orgs/${orgId}`,
timeout: 120_000,
accessToken,
data: {},
});
},

async getOrg(accessToken: string) {
return await portalApiHelper.post({
accessToken, path: '/v1/orgs:search',
}) as { orgs: { id: string }[] };
return await portalApiHelper.post({ accessToken, path: '/v1/orgs:search' }) as { orgs: { id: string }[] };
},

async getOrgDetails(accessToken: string, orgId: string) {
return portalApiHelper.get({
accessToken, path: `/v1/orgs/${orgId}`,
});
return portalApiHelper.get({ accessToken, path: `/v1/orgs/${orgId}` });
},

async inviteUserToOrg(accessToken: string, orgId: string, username: string, role: PortalUserRoles) {
return portalApiHelper.post({
path: `/v1/orgs/${orgId}/members`,
accessToken,
data: {
username, role,
},
data: { username, role },
});
},

62 changes: 51 additions & 11 deletions playwright-tests/docs/setup-env-portal.md
Original file line number Diff line number Diff line change
@@ -12,25 +12,65 @@
* **Run docker container manually:**
run the following commands:
<pre>
PMM_VERSION=2.39.0
docker pull percona/pmm-server:$PMM_VERSION
PMM_SERVER_IMAGE=percona/pmm-server:2.39.0

docker pull $PMM_SERVER_IMAGE
docker volume create pmm-data
docker run --detach --restart always \
--publish 443:443 \
-v pmm-data:/srv \
--name pmm-server \
-e PERCONA_PORTAL_URL=https://portal-dev.percona.com \
-e PERCONA_TEST_PLATFORM_ADDRESS=https://check-dev.percona.com:443 \
-e PERCONA_TEST_PLATFORM_PUBLIC_KEY=RWTg+ZmCCjt7O8eWeAmTLAqW+1ozUbpRSKSwNTmO+exlS5KEIPYWuYdX \
-e PERCONA_TEST_CHECKS_PUBLIC_KEY=RWTg+ZmCCjt7O8eWeAmTLAqW+1ozUbpRSKSwNTmO+exlS5KEIPYWuYdX \
-e PERCONA_TEST_VERSION_SERVICE_URL=https://check-dev.percona.com/versions/v1 \
percona/pmm-server:$PMM_VERSION
--publish 443:443 \
-v pmm-data:/srv \
--name pmm-server \
-e ENABLE_RBAC=1 \
-e PERCONA_PORTAL_URL=https://portal-dev.percona.com \
-e PERCONA_TEST_PLATFORM_ADDRESS=https://check-dev.percona.com:443 \
-e PERCONA_TEST_PLATFORM_PUBLIC_KEY=RWTg+ZmCCjt7O8eWeAmTLAqW+1ozUbpRSKSwNTmO+exlS5KEIPYWuYdX \
-e PERCONA_TEST_CHECKS_PUBLIC_KEY=RWTg+ZmCCjt7O8eWeAmTLAqW+1ozUbpRSKSwNTmO+exlS5KEIPYWuYdX \
-e PERCONA_TEST_VERSION_SERVICE_URL=https://check-dev.percona.com/versions/v1 \
-e GF_AUTH_OAUTH_ALLOW_INSECURE_EMAIL_LOOKUP=1 \
$PMM_SERVER_IMAGE
</pre>

### Setup PMM Client
PMM Client may be installed in multiple ways:
* using pmm-framework,
* percona-release and packages manager
* **install script**
run the following commands:
<pre>
PMM_VERSION=2.39.0

### install local agent
path=/usr/local/percona/pmm2
#wget -4P /tmp/ --progress=dot:giga "https://raw.githubusercontent.com/Percona-QA/package-testing/master/scripts/pmm2_client_install_tarball.sh"
(cd /tmp && curl -O https://raw.githubusercontent.com/Percona-QA/package-testing/master/scripts/pmm2_client_install_tarball.sh)
#sudo bash -x /tmp/pmm2_client_install_tarball.sh -v $PMM_VERSION -r PR-2974-fddced9
sudo bash -x /tmp/pmm2_client_install_tarball.sh -v $PMM_VERSION

### Setup local agent
sudo pmm-admin config --force --server-insecure-tls --metrics-mode=auto --agent-password=pmm-pass --server-url=https://admin:admin@127.0.0.1:443
sudo pmm-agent setup --force --config-file=${path}/config/pmm-agent.yaml --server-address=127.0.0.1:443 --server-insecure-tls --server-username=admin --server-password=admin
sudo pmm-agent --config-file=${path}/config/pmm-agent.yaml > pmm-agent.log 2>&1 &

### verify pmm-admin is up and connected
pmm-admin status
</pre>

### Set required ENV variables

**IMPORTANT!** _Make sure ".env" file is in git ignore and will not be committed!_

create ".env" file in the project root dir with the following content:
<pre>
OAUTH_DEV_HOST={string value}
OKTA_TOKEN={string value}
OAUTH_ISSUER_URL={string value}

SERVICENOW_LOGIN='{string value}'
SERVICENOW_PASSWORD='{string value}'
SERVICENOW_DEV_URL='{string value}'
</pre>

### Run Portal tests
<pre>
npx playwright test --project=Portal -g @portal --headed
</pre>
Original file line number Diff line number Diff line change
@@ -4,8 +4,10 @@ const pmmServerCommands = {
getNodeDetails: async (nodeId: string) => {
const response = (await executeCommand(`sudo docker exec -u postgres pmm-integration-server psql -U pmm-managed -c "SELECT * FROM nodes WHERE node_id = '${nodeId}'; " | grep '/node_id/'`))
.stdout.replaceAll('|', '').replace(/ +(?= )/g, '').split(' ').filter((row) => row !== '');
return { nodeId: response[0], nodeType: response[1], nodeName: response[2], address: response[5] };
return {
nodeId: response[0], nodeType: response[1], nodeName: response[2], address: response[5],
};
},
}
};

export default pmmServerCommands;
4 changes: 3 additions & 1 deletion playwright-tests/helpers/enums/wait.ts
Original file line number Diff line number Diff line change
@@ -9,12 +9,14 @@ enum Wait {
OneSecond = oneSecond,
TwoSeconds = 2 * oneSecond,
TenSeconds = 10 * oneSecond,
OneMinute = oneMin,
OneMinute = 60 * oneSecond,
TwoMinutes = 2 * oneMin,
ThreeMinutes = 3 * oneMin,
FiveMinutes = 5 * oneMin,
TenMinutes = 10 * oneMin,
TwentyMinutes = 20 * oneMin,
ToastMessage = 30 * oneSecond,
PageLoad = 30 * oneSecond,
}

export default Wait;
6 changes: 4 additions & 2 deletions playwright-tests/pages/common.page.ts
Original file line number Diff line number Diff line change
@@ -4,14 +4,16 @@ import ToastMessage from '@components/toast-message-modal';
import OptionsMenu from '@components/options-menu';
import { expect } from '@helpers/test-helper';
import grafanaHelper from '@helpers/grafana-helper';
import NetworkTools from '@components/network-tools';

export class CommonPage {
PAGE_HEADING_LOCATOR: Locator = this.page.locator('//h1');

network = new NetworkTools(this.page);
toastMessage = new ToastMessage(this.page);
sideMenu = new LeftNavigationMenu(this.page);
optionMenu = new OptionsMenu(this.page);

PAGE_HEADING_LOCATOR = this.page.locator('//h1');

elements: object = {
mainView: this.page.locator('//*[@class="main-view"]'),
emptyBlock: this.page.getByTestId('empty-block'),
12 changes: 4 additions & 8 deletions playwright-tests/pages/home-dashboard.page.ts
Original file line number Diff line number Diff line change
@@ -6,17 +6,13 @@ import PmmMenu from '@components/dashboards/pmm-menu';
import { BaseDashboard } from './dashboards/base-dashboard.page';

export default class HomeDashboardPage extends BaseDashboard {
/** Page "path" and "heading" defaults to the "Home Dashboard Page" */
// url: 'graph/d/pmm-home/home-dashboard?orgId=1&refresh=1m&from=now-5m&to=now',
PAGE_PATH = 'graph/d/pmm-home/home-dashboard?orgId=1&refresh=1m';
PAGE_HEADING = 'Home Dashboard';
readonly PAGE_PATH = 'graph/d/pmm-home/home-dashboard?orgId=1&refresh=1m';
readonly PAGE_HEADING = 'Home Dashboard';

pmmUpgrade = new PmmUpgrade(this.page);
upgradeModal = new UpgradeModal(this.page);
pmmMenu = new PmmMenu(this.page);

landingUrl = 'graph/d/pmm-home/home-dashboard?orgId=1&refresh=1m';

/**
* Opens given Page entering url into the address field.
*/
@@ -25,7 +21,7 @@ export default class HomeDashboardPage extends BaseDashboard {
};

async waitToBeOpened() {
await this.pmmUpgrade.containers.upgradeContainer.waitFor({ state: 'visible', timeout: Wait.OneMinute });
await this.PAGE_HEADING_LOCATOR.waitFor({ state: 'visible', timeout: Wait.OneMinute });
await expect(this.page).toHaveURL(this.PAGE_PATH);
}
upgradePmm = async () => {
@@ -39,7 +35,7 @@ export default class HomeDashboardPage extends BaseDashboard {

await this.upgradeModal.containers.modalContainer.waitFor({ state: 'visible', timeout: Wait.OneMinute });
await this.upgradeModal.elements.upgradeInProgressHeader
.waitFor({ state: 'visible', timeout: Wait.OneMinute as number });
.waitFor({ state: 'visible', timeout: Wait.OneMinute });
await expect(this.upgradeModal.elements.upgradeSuccess)
.toHaveText(this.upgradeModal.messages.upgradeSuccess(availableVersion) as string, { timeout: Wait.TenMinutes });
await this.upgradeModal.buttons.close.click();
22 changes: 22 additions & 0 deletions playwright-tests/pages/login-platform.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CommonPage } from '@pages/common.page';
import Wait from '@helpers/enums/wait';

export default class LoginPlatformPage extends CommonPage {
readonly PAGE_PATH = 'https://id-dev.percona.com/signin';
readonly PAGE_HEADING = 'Sign in to Percona Platform';

elements: any = {
usernameInput: this.page.locator('//input[@name="username"]'),
passwordInput: this.page.locator('//input[@name="password"]'),
nextButton: this.page.locator('//input[@id="idp-discovery-submit"]'),
signInButton: this.page.locator('//input[@id="okta-signin-submit"]'),
};

login = async (username: string, password: string) => {
await this.elements.usernameInput.type(username);
await this.elements.nextButton.click();
await this.elements.passwordInput.type(password);
await this.elements.signInButton.click();
await this.elements.signInButton.waitFor({ state: 'detached', timeout: Wait.ToastMessage });
};
}
Loading