Skip to content

Commit

Permalink
PMM-12710 api breaking changes (#789)
Browse files Browse the repository at this point in the history
  • Loading branch information
matejkubinec authored Sep 26, 2024
1 parent 29f4fd9 commit 384e8d0
Show file tree
Hide file tree
Showing 68 changed files with 775 additions and 625 deletions.
16 changes: 15 additions & 1 deletion playwright-tests/api/helpers/api-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const getConfiguredRestApi = async (): Promise<APIRequestContext> => {
const apiHelper = {
// TODO: remove in favor of xxxPage.network.suppressTour().
confirmTour: async (page: Page) => {
await page.route('**/v1/user', async (route) => {
await page.route('**/v1/users/me', async (route) => {
await route.fulfill({
status: 200,
body: JSON.stringify({
Expand Down Expand Up @@ -75,6 +75,20 @@ const apiHelper = {
return response;
},

/**
* Implements HTTP PUT to PMM Server API
*
* @param path API endpoint path
* @param payload request body {@code Object}
* @return Promise<APIResponse> instance
*/
put: async (path: string, payload: object): Promise<APIResponse> => {
console.log(`PUT: ${path}\nPayload: ${JSON.stringify(payload)}`);
const response = await (await getConfiguredRestApi()).put(path, { data: payload });
expect(response.status(), `Status: ${response.status()} ${response.statusText()}`).toEqual(200);
return response;
},

/**
* Implements HTTP DELETE to PMM Server API
* Request parameters can be configured with original client options.
Expand Down
2 changes: 1 addition & 1 deletion playwright-tests/api/inventory.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ interface NodeDetails {

export const inventoryApi = {
async listNodes(): Promise<ListNodes> {
return await (await apiHelper.post('v1/inventory/Nodes/List', {})).json() as ListNodes;
return await (await apiHelper.get('v1/management/nodes', {})).json() as ListNodes;
},
};
13 changes: 6 additions & 7 deletions playwright-tests/api/management.api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import apiHelper from '@api/helpers/api-helper';
import { ListRoles, Role } from '@api/api';

const ROLE_CREATE = '/v1/management/Role/Create';
const ROLE_LIST = '/v1/management/Role/List';
const ROLE_DELETE = '/v1/management/Role/Delete';
const PATH = '/v1/accesscontrol/roles';
/**
* v1 API: "management" endpoints requests collection
*/
Expand All @@ -19,22 +17,23 @@ export const managementApi = {
const payload: Role = {
title, description, filter,
};
return (await (await apiHelper.post(ROLE_CREATE, payload)).json()).role_id as number;
return (await (await apiHelper.post(PATH, payload)).json()).role_id as number;
},

listRoles: async (): Promise<ListRoles> => {
return await (await apiHelper.post(ROLE_LIST, {})).json() as ListRoles;
return await (await apiHelper.get(PATH, {})).json() as ListRoles;
},

listServices: async (): Promise<any | undefined> => {
const response = await apiHelper.post('/v1/management/Service/List', {});
const response = await apiHelper.get('/v1/management/services', {});
return response.json();
},

async deleteRole(roleTile: string) {
const searchResult = (await this.listRoles()).roles.find((role: Role) => role.title === roleTile);
if (searchResult) {
await apiHelper.post(ROLE_DELETE, { role_id: searchResult.role_id, replacement_role_id: 1 });
const data = { role_id: searchResult.role_id, replacement_role_id: 1 };
await apiHelper.delete(`${PATH}/${searchResult.role_id}`, { data });
}
},
};
2 changes: 1 addition & 1 deletion playwright-tests/pages/page-components/network-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default class NetworkTools {

// TODO: move it to api calls way
suppressTour = async () => {
await this.page.route('**/v1/user', async (route) => {
await this.page.route('**/v1/users/me', async (route) => {
await route.fulfill({
status: 200,
body: JSON.stringify({
Expand Down
7 changes: 3 additions & 4 deletions playwright-tests/tests/configuration/api/settings.api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import apiHelper from '@api/helpers/api-helper';
import { APIResponse } from 'playwright-core';

const PATH_GET = 'v1/Settings/Get';
const PATH_CHANGE = 'v1/Settings/Change';
const PATH = 'v1/server/settings';

export interface Settings {
pmm_public_address: string;
Expand All @@ -28,12 +27,12 @@ export const settingsApi = {
* @returns if property found - property value; {@code undefined} otherwise
*/
async getSettingsProperty(name: SettingProperty): Promise<string | undefined> {
const responseBody: SettingObject = await (await apiHelper.post(PATH_GET, {})).json();
const responseBody: SettingObject = await (await apiHelper.post(PATH, {})).json();
console.log(`Response:\n${JSON.stringify(responseBody)}`);
return Object.hasOwn(responseBody.settings, name) ? responseBody.settings[name] as string : undefined;
},

changeSettings: async (settingsData: Settings): Promise<APIResponse> => {
return apiHelper.post(PATH_CHANGE, { data: settingsData });
return apiHelper.put(PATH, { data: settingsData });
},
};
3 changes: 2 additions & 1 deletion tests/DbaaS/verifyDBaaSPXCCluster_test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const assert = require('assert');
const { SERVICE_TYPE } = require('../helper/constants');

const { dbaasAPI, dbaasPage, locationsPage } = inject();
const clusterName = 'minikube';
Expand Down Expand Up @@ -167,7 +168,7 @@ Data(pxcDBClusterDetails).Scenario(

await dbaasPage.dbaasQANCheck(pxc_cluster_name, serviceName, serviceName);
await dbaasPage.pxcClusterMetricCheck(pxc_cluster_name, serviceName, serviceName, haproxyNodeName);
await dbaasPage.dbClusterAgentStatusCheck(pxc_cluster_name, serviceName, 'MYSQL_SERVICE');
await dbaasPage.dbClusterAgentStatusCheck(pxc_cluster_name, serviceName, SERVICE_TYPE.MYSQL);
},
);

Expand Down
2 changes: 1 addition & 1 deletion tests/DbaaS/verifyDbaaSMongoDBCluster_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Scenario(

// await dbaasPage.psmdbClusterMetricCheck(psmdb_cluster, serviceName, serviceName, replSet);
// await dbaasPage.dbaasQANCheck(psmdb_cluster, serviceName, serviceName);
// await dbaasPage.dbClusterAgentStatusCheck(psmdb_cluster, serviceName, 'MONGODB_SERVICE');
// await dbaasPage.dbClusterAgentStatusCheck(psmdb_cluster, serviceName, SERVICE_TYPE.MONGODB);
// },
// );

Expand Down
2 changes: 1 addition & 1 deletion tests/QAN/api/qanAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = {
period_start_to: toTime,
totals: false,
};
const resp = await I.sendPostRequest('v0/qan/ObjectDetails/GetMetrics', data, headers);
const resp = await I.sendPostRequest('/v1/qan:getMetrics', data, headers);

return resp;
},
Expand Down
44 changes: 25 additions & 19 deletions tests/QAN/timerange_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ Scenario(
async ({
I, adminPage, queryAnalyticsPage,
}) => {
const date = moment().format('YYYY-MM-DD');
const fromString = Date.parse(`${date} 00:00:00`);
const toString = Date.parse(`${date} 23:59:59`);
const currentDate = moment();
const date = currentDate.format('YYYY-MM-DD');

await I.seeInCurrentUrl('from=now-5m&to=now');
await queryAnalyticsPage.data.selectRow(1);
queryAnalyticsPage.data.selectRow(1);
queryAnalyticsPage.waitForLoaded();
await I.seeElement(queryAnalyticsPage.data.root);
await adminPage.setAbsoluteTimeRange(`${date} 00:00:00`, `${date} 23:59:59`);
await I.seeInCurrentUrl(`from=${fromString}&to=${toString}`);
await queryAnalyticsPage.data.selectRow(1);
adminPage.setAbsoluteTimeRange(`${date} 00:00:00`, `${date} 23:59:59`);
queryAnalyticsPage.waitForLoaded();
await I.seeElement(queryAnalyticsPage.data.root);
adminPage.verifySelectedTimeRange(`${date} 00:00:00`, `${date} 23:59:59`);

const url = await I.grabCurrentUrl();

I.assertContain(url.split('from=')[1].replaceAll('%20', ' '), `${currentDate.format('ddd MMM DD YYYY')} 00:00:00`, 'From Date is not correct');
I.assertContain(url.split('to=')[1].replaceAll('%20', ' '), `${currentDate.format('ddd MMM DD YYYY')} 23:59:59`, 'To Date is not correct');
},
);

Expand Down Expand Up @@ -151,19 +151,25 @@ Scenario(
const to = dateTime.format('YYYY-MM-DD HH:mm:ss');
const from = moment(dateTime).subtract(1, 'hours').format('YYYY-MM-DD HH:mm:ss');

await adminPage.setAbsoluteTimeRange(from, to);
adminPage.setAbsoluteTimeRange(from, to);
queryAnalyticsPage.waitForLoaded();
await I.seeInCurrentUrl(`&from=${moment(from).format('ddd%20MMM%20D%20YYYY%20HH:mm:ss')}`);
await I.seeInCurrentUrl(`&to=${moment(to).format('ddd%20MMM%20D%20YYYY%20HH:mm:ss')}`);
I.waitForVisible(queryAnalyticsPage.buttons.copyButton);

const url = await I.grabCurrentUrl();

I.assertContain(url.split('from=')[1].replaceAll('%20', ' '), moment(from).format('ddd MMM DD YYYY HH:mm:ss'), 'Url does not contain selected from date time');
I.assertContain(url.split('to=')[1].replaceAll('%20', ' '), moment(to).format('ddd MMM DD YYYY HH:mm:ss'), 'Url does not contain selected to date time');

I.click(queryAnalyticsPage.buttons.copyButton);
const clipBoardUrl = await I.grabTextFrom(queryAnalyticsPage.elements.clipboardLink);

const url = await I.grabTextFrom(queryAnalyticsPage.elements.clipboardLink);
I.amOnPage(clipBoardUrl);
queryAnalyticsPage.waitForLoaded();
const secondUrl = await I.grabCurrentUrl();

adminPage.verifySelectedTimeRange(from, to);

await I.openNewTab();
await I.amOnPage(url.match(/\bhttps?:\/\/\S+/gi)[0]);
await I.seeInCurrentUrl(`&from=${moment(from).utc().format('ddd%20MMM%20D%20YYYY%20HH:mm:ss')}`);
await I.seeInCurrentUrl(`&to=${moment(to).utc().format('ddd%20MMM%20D%20YYYY%20HH:mm:ss')}`);
I.assertContain(secondUrl.split('from=')[1].replaceAll('%20', ' '), moment(from).utc().format('ddd MMM DD YYYY HH:mm:ss'), 'Second Url does not contain selected from date time');
I.assertContain(secondUrl.split('to=')[1].replaceAll('%20', ' '), moment(to).utc().format('ddd MMM DD YYYY HH:mm:ss'), 'Second Url does not contain selected to date time');
},
);

Expand Down
2 changes: 1 addition & 1 deletion tests/administration/serviceAccounts_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Scenario('PMM-T1884 Verify disabling service account @service-account', async ({
await serviceAccountsPage.disableServiceAccount(serviceAccountUsername);
await I.wait(10);
const psContainerName = await I.verifyCommand('docker ps | grep ps_pmm | awk \'{print $NF}\'');
const responseDisabled = await I.verifyCommand(`sudo docker exec ${psContainerName} pmm-admin list`, '', 'fail');
const responseDisabled = await I.verifyCommand(`docker exec ${psContainerName} pmm-admin list`, '', 'fail');
const expectedDisabledMessage = 'Unauthorized. Please check username and password.';

I.assertEqual(
Expand Down
21 changes: 11 additions & 10 deletions tests/advisors/pages/api/advisorsAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
async getSecurityChecksResults() {
const headers = { Authorization: `Basic ${await I.getAuth()}` };

const resp = await I.sendPostRequest('v1/management/SecurityChecks/GetCheckResults', {}, headers);
const resp = await I.sendGetRequest('v1/advisor/checks', headers);

assert.ok(
resp.status === 200,
Expand All @@ -25,7 +25,7 @@ module.exports = {
const headers = { Authorization: `Basic ${await I.getAuth()}` };
const body = checkNamesArray ? { names: checkNamesArray } : {};

const resp = await I.sendPostRequest('v1/management/SecurityChecks/Start', body, headers);
const resp = await I.sendPostRequest('v1/advisors/checks:start', body, headers);

assert.ok(
resp.status === 200,
Expand All @@ -37,7 +37,7 @@ module.exports = {
const headers = { Authorization: `Basic ${await I.getAuth()}` };
const body = { service_id, page_params: { page_size: 25, index: 0 } };

const resp = await I.sendPostRequest('v1/management/SecurityChecks/FailedChecks', body, headers);
const resp = await I.sendPostRequest('v1/advisors/checks/failed', body, headers);

assert.ok(
resp.status === 200,
Expand All @@ -51,6 +51,7 @@ module.exports = {
const headers = { Authorization: `Basic ${await I.getAuth()}` };
const body = { alert_id, silence };

// todo: api-breaking-changes
const resp = await I.sendPostRequest('v1/management/SecurityChecks/ToggleCheckAlert', body, headers);

assert.ok(
Expand Down Expand Up @@ -104,7 +105,7 @@ module.exports = {
}],
};

const resp = await I.sendPostRequest('v1/management/SecurityChecks/Change', body, headers);
const resp = await I.sendPostRequest('v1/advisors/checks:batchChange', body, headers);

assert.ok(
resp.status === 200,
Expand All @@ -121,15 +122,15 @@ module.exports = {
}],
};

const resp = await I.sendPostRequest('v1/management/SecurityChecks/Change', body, headers);
const resp = await I.sendPostRequest('v1/advisors/checks:batchChange', body, headers);

assert.ok(
resp.status === 200,
`Failed to disable Security Check "${checkName}". Response message is "${resp.data.message}"`,
);
},

async changeCheckInterval(checkName, interval = 'FREQUENT') {
async changeCheckInterval(checkName, interval = 'ADVISOR_CHECK_INTERVAL_FREQUENT') {
const headers = { Authorization: `Basic ${await I.getAuth()}` };
const body = {
params: [{
Expand All @@ -138,7 +139,7 @@ module.exports = {
}],
};

const resp = await I.sendPostRequest('v1/management/SecurityChecks/Change', body, headers);
const resp = await I.sendPostRequest('v1/advisors/checks:batchChange', body, headers);

assert.ok(
resp.status === 200,
Expand All @@ -148,7 +149,7 @@ module.exports = {

async getAllChecksList() {
const headers = { Authorization: `Basic ${await I.getAuth()}` };
const resp = await I.sendPostRequest('v1/management/SecurityChecks/List', {}, headers);
const resp = await I.sendGetRequest('v1/advisors/checks', headers);

return resp.data.checks;
},
Expand All @@ -162,8 +163,8 @@ module.exports = {
await I.asyncWaitFor(this.getAllChecksList, 60);
const allChecks = await this.getAllChecksList();

allChecks.forEach(({ name }) => body.params.push({ name, interval: 'STANDARD' }));
const resp = await I.sendPostRequest('v1/management/SecurityChecks/Change', body, headers);
allChecks.forEach(({ name }) => body.params.push({ name, interval: 'ADVISOR_CHECK_INTERVAL_STANDARD' }));
const resp = await I.sendPostRequest('v1/advisors/checks:batchChange', body, headers);

assert.ok(
resp.status === 200,
Expand Down
6 changes: 3 additions & 3 deletions tests/advisors/stt/checksExecution_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ let serviceId;
const intervalsTests = new DataTable(['interval', 'intervalValue']);

// TODO: unskip after https://jira.percona.com/browse/PMM-8051
// intervalsTests.add(['frequent_interval', 'FREQUENT']);
intervalsTests.add(['standard_interval', 'STANDARD']);
// intervalsTests.add(['rare_interval', 'RARE']);
// intervalsTests.add(['frequent_interval', 'ADVISOR_CHECK_INTERVAL_FREQUENT']);
intervalsTests.add(['standard_interval', 'ADVISOR_CHECK_INTERVAL_STANDARD']);
// intervalsTests.add(['rare_interval', 'ADVISOR_CHECK_INTERVAL_RARE']);

const cleanup = async () => {
await settingsAPI.apiEnableSTT();
Expand Down
3 changes: 2 additions & 1 deletion tests/advisors/stt/databaseChecks_test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const assert = require('assert');
const { SERVICE_TYPE } = require('../../helper/constants');

const {
advisorsPage, databaseChecksPage, codeceptjsConfig, psMySql,
Expand Down Expand Up @@ -173,7 +174,7 @@ Scenario.skip(
I.see(psServiceName);
await inventoryAPI.verifyServiceExistsAndHasRunningStatus(
{
serviceType: 'MYSQL_SERVICE',
serviceType: SERVICE_TYPE.MYSQL,
service: 'mysql',
},
psServiceName,
Expand Down
Loading

0 comments on commit 384e8d0

Please sign in to comment.