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

Add Sharding Support to PSMDB Demand Backup Test #918

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6acb71c
Add a firts step for Sharing for MongoDB Test
edithturn Nov 28, 2024
b6427dc
Merge branch 'main' into feature/e2e-test-psmdb-sharding
edithturn Nov 29, 2024
e9180d2
Fix toBeChecked and toHaveValue for Sharding
edithturn Dec 2, 2024
2607526
fixing create clustr
edithturn Dec 2, 2024
23ea4d6
add prepareMongoDBTest and Configure Sharding functions
edithturn Dec 2, 2024
50bc595
If sharding is true no replicaset
edithturn Dec 9, 2024
f13b304
Enabled Sharding and ReplicaSet issue Fixed
edithturn Dec 9, 2024
cb0df55
Step Restore backup Working
edithturn Dec 10, 2024
ebed629
Sharding Test for MongoDB Implementation tested
edithturn Dec 10, 2024
f2a47fa
Cleaning comments
edithturn Dec 10, 2024
0bd8c2f
Merge branch 'main' into feature/e2e-test-psmdb-sharding
tplavcic Dec 10, 2024
209480e
Add validateMongoDBSharding
edithturn Dec 11, 2024
fd15ab1
Merge branch 'main' into feature/e2e-test-psmdb-sharding
edithturn Dec 11, 2024
7d7d9a7
Validate Sharding after Restore
edithturn Dec 12, 2024
c985e07
Merge branch 'main' into feature/e2e-test-psmdb-sharding
edithturn Dec 12, 2024
9a34e44
Merge branch 'main' into feature/e2e-test-psmdb-sharding
tplavcic Dec 13, 2024
428c1de
Merge branch 'main' into feature/e2e-test-psmdb-sharding
tplavcic Jan 8, 2025
ab026d4
Add step step for sharding
edithturn Dec 23, 2024
1d87e7f
Add Helm Charts Guide for our Readme (#988)
edithturn Jan 9, 2025
48106fd
chore(deps): bump google.golang.org/protobuf from 1.36.0 to 1.36.2 (#…
dependabot[bot] Jan 9, 2025
330c46f
chore(deps): bump golang.org/x/time from 0.7.0 to 0.9.0 (#983)
dependabot[bot] Jan 9, 2025
3d04a71
EVEREST-107 fix tiltfile - everest-operator directory
recharte Jan 10, 2025
90dc00c
EVEREST-1794 Extend help description for `everestctl namespaces remov…
maxkondr Jan 10, 2025
455a015
fix: do not block engines request based on RBAC (#979)
fabio-silva Jan 10, 2025
0cde310
Everest-1717 | RBAC UI tests (#951)
fabio-silva Jan 10, 2025
5dd703c
EVEREST-1306: fix strings to numbers (#759)
solovevayaroslavna Jan 10, 2025
630742c
EVEREST-1709 | RBAC unit tests (#990)
mayankshah1607 Jan 13, 2025
32e875e
EVEREST-1709 | Update RBAC permissions & tests (#998)
mayankshah1607 Jan 13, 2025
46d144c
EVEREST-1816 | [CLI] support openshift installation (#999)
mayankshah1607 Jan 13, 2025
ebff4b9
increase tests timeout (#1002)
oksana-grishchenko Jan 13, 2025
4d5bb14
update go modules (#1006)
mayankshah1607 Jan 13, 2025
a63a3db
Everest 1673 custom helm dir in db namespaces (#1007)
oksana-grishchenko Jan 14, 2025
4663cf4
EVEREST-1816 | update kube-state-metrics settings for openshift insta…
mayankshah1607 Jan 15, 2025
20c7837
Resolved merge conflicts in go.mod and go.sum
edithturn Jan 16, 2025
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
344 changes: 344 additions & 0 deletions ui/apps/everest/.e2e/release/demand-backup-psmdb-sharding.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
// everest
// Copyright (C) 2023 Percona LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { expect, test } from '@playwright/test';
import {
deleteDbCluster,
gotoDbClusterBackups,
gotoDbClusterRestores,
} from '@e2e/utils/db-clusters-list';
import { getTokenFromLocalStorage } from '@e2e/utils/localStorage';
import { getClusterDetailedInfo } from '@e2e/utils/storage-class';
import {
moveForward,
submitWizard,
populateBasicInformation,
populateResources,
populateAdvancedConfig,
populateMonitoringModalForm,
} from '@e2e/utils/db-wizard';
import { EVEREST_CI_NAMESPACES } from '@e2e/constants';
import {
waitForStatus,
waitForDelete,
findRowAndClickActions,
} from '@e2e/utils/table';
import { checkError } from '@e2e/utils/generic';
import {
deleteMonitoringInstance,
listMonitoringInstances,
} from '@e2e/utils/monitoring-instance';
import { clickOnDemandBackup } from '@e2e/pr/db-cluster-details/utils';
import {
queryPSMDB,
prepareMongoDBTestDB,
validateMongoDBSharding,
configureMongoDBSharding,
dropTestDB,
queryTestDB,
} from '@e2e/utils/db-cmd-line';

export let isShardingEnabled = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems strange exporting this from the test and importing it into helper functions. Let's create a function psmdbShardingEnabled in db-cmd-line.ts and then use it inside the same file.


const {
MONITORING_URL,
MONITORING_USER,
MONITORING_PASSWORD,
SELECT_DB,
SELECT_SIZE,
} = process.env;
let token: string;

const db = 'psmdb';
const size = 3;

test.describe.configure({ retries: 0 });

test.describe(
'Demand backup psmdb',
{
tag: '@release',
},
() => {
test.skip(
() =>
(SELECT_DB !== db && !!SELECT_DB) ||
(SELECT_SIZE !== size.toString() && !!SELECT_SIZE)
);
test.describe.configure({ timeout: 720000 });

const clusterName = `${db}-${size}-dembkp`;

let storageClasses = [];
const namespace = EVEREST_CI_NAMESPACES.EVEREST_UI;
const monitoringName = `${db}-${size}-pmm`;
const baseBackupName = `dembkp-${db}-${size}`;

test.beforeAll(async ({ request }) => {
token = await getTokenFromLocalStorage();

const { storageClassNames = [] } = await getClusterDetailedInfo(
token,
request
);
storageClasses = storageClassNames;
});

test.afterAll(async ({ request }) => {
// we try to delete all monitoring instances because cluster creation expects that none exist
// (monitoring instance is added in the form where the warning that none exist is visible)
const monitoringInstances = await listMonitoringInstances(
request,
namespace,
token
);
for (const instance of monitoringInstances) {
await deleteMonitoringInstance(
request,
namespace,
instance.name,
token
);
}
});

test(`Cluster creation [${db} size ${size}]`, async ({ page, request }) => {
expect(storageClasses.length).toBeGreaterThan(0);

await page.goto('/databases');
await page.getByTestId('add-db-cluster-button').waitFor();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this part should be moved to utils to avoid duplication 🤔 we call the cluster creation button in a lot of places

await page.getByTestId('add-db-cluster-button').click();
await page.getByTestId(`add-db-cluster-button-${db}`).click();

await test.step('Populate basic information', async () => {
await populateBasicInformation(
page,
namespace,
clusterName,
db,
storageClasses[0],
false
);
});

// Step to activate Sharding
await test.step('Activate sharding', async () => {
const shardingCheckbox = page
.getByTestId('switch-input-sharding')
.getByRole('checkbox');
const isChecked = await shardingCheckbox?.isChecked();
if (!isChecked) {
if (shardingCheckbox) {
isShardingEnabled = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we create a new function in db-cmd-line.ts we don't need this here. Also we want to check if sharding is actually enabled in the backend (api call) and not did we just click on something in UI.

await shardingCheckbox.click();
}
}
await expect(shardingCheckbox).toBeChecked();
});

await moveForward(page); // Move forward after activating sharding

await test.step('Populate resources', async () => {
await page
.getByRole('button')
.getByText(size + ' node')
.click();
await expect(page.getByText('Nº nodes: ' + size)).toBeVisible();
await populateResources(page, 0.6, 1, 1, size);
// await moveForward(page);
});

// Step to set number of shards
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment since test description below has the same.

await test.step('Set number of shards', async () => {
const shardsInput = await page.getByTestId('text-input-shard-nr');
await expect(shardsInput).toBeVisible();
await shardsInput.fill('2');
await expect(shardsInput).toHaveValue('2');
await moveForward(page);
});

await test.step('Populate backups', async () => {
await moveForward(page);
});

await test.step('Populate advanced db config', async () => {
await populateAdvancedConfig(page, db, '', true, '');
await moveForward(page);
});

await test.step('Populate monitoring', async () => {
await populateMonitoringModalForm(
page,
monitoringName,
namespace,
MONITORING_URL,
MONITORING_USER,
MONITORING_PASSWORD,
false
);
await page.getByTestId('switch-input-monitoring').click();
await expect(
page.getByTestId('text-input-monitoring-instance')
).toHaveValue(monitoringName);
});

await test.step('Submit wizard', async () => {
await submitWizard(page);

await expect(
page.getByText('Awesome! Your database is being created!')
).toBeVisible();
});

// go to db list and check status
await test.step('Check db list and status', async () => {
await page.goto('/databases');
await waitForStatus(page, clusterName, 'Initializing', 15000);
await waitForStatus(page, clusterName, 'Up', 600000);
});

await test.step('Check db cluster k8s object options', async () => {
const response = await request.get(
`/v1/namespaces/${namespace}/database-clusters`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);

await checkError(response);

// TODO: replace with correct payload typings from GET DB Clusters
const { items: clusters } = await response.json();

const addedCluster = clusters.find(
(cluster) => cluster.metadata.name === clusterName
);

expect(addedCluster).not.toBeUndefined();
expect(addedCluster?.spec.engine.type).toBe(db);
expect(addedCluster?.spec.engine.replicas).toBe(size);
expect(['600m', '0.6']).toContain(
addedCluster?.spec.engine.resources?.cpu.toString()
);
expect(addedCluster?.spec.engine.resources?.memory.toString()).toBe(
'1G'
);
expect(addedCluster?.spec.engine.storage.size.toString()).toBe('1Gi');
expect(addedCluster?.spec.proxy.expose.type).toBe('internal');

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add something like:

expect(addedCluster?.spec.sharding.enabled).toBe(true)
expect(addedCluster?.spec.sharding.shards).toBe(2)
expect(addedCluster?.spec.sharding.configServer.replicas).toBe(3)
expect(addedCluster?.spec.proxy.replicas).toBe(3)

//if (db != 'psmdb') {
// expect(addedCluster?.spec.proxy.replicas).toBe(size);
//}
Comment on lines +243 to +245
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

});
});

// Add data in MondoDB
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment since test description below has the same.

test(`Add data [${db} size ${size}]`, async () => {
await prepareMongoDBTestDB(clusterName, namespace);
});

// Add MongoDB-specific configuration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment since test description below has the same.

test(`Setup MongoDB-specific sharding [${db} size ${size}]`, async () => {
await configureMongoDBSharding(clusterName, namespace);
});

// Validate Sharding for MongoDB
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment since test description below has the same.

test(`Validate Sharding for MongoDB [${db} size ${size}]`, async () => {
await validateMongoDBSharding(clusterName, namespace);
});

test(`Create demand backup [${db} size ${size}]`, async ({ page }) => {
await gotoDbClusterBackups(page, clusterName);
await clickOnDemandBackup(page);
await page.getByTestId('text-input-name').fill(baseBackupName + '-1');
await expect(page.getByTestId('text-input-name')).not.toBeEmpty();
await expect(
page.getByTestId('text-input-storage-location')
).not.toBeEmpty();
await page.getByTestId('form-dialog-create').click();

await waitForStatus(page, baseBackupName + '-1', 'Succeeded', 500000);
});

test(`Delete data [${db} size ${size}]`, async () => {
await dropTestDB(clusterName, namespace);
});

test(`Restore cluster [${db} size ${size}]`, async ({ page }) => {
await gotoDbClusterBackups(page, clusterName);
await findRowAndClickActions(
page,
baseBackupName + '-1',
'Restore to this DB'
);
await expect(
page.getByTestId('select-input-backup-name')
).not.toBeEmpty();
await page.getByTestId('form-dialog-restore').click();

await page.goto('/databases');
await waitForStatus(page, clusterName, 'Restoring', 30000);
await waitForStatus(page, clusterName, 'Up', 600000);

await gotoDbClusterRestores(page, clusterName);
// we select based on backup source since restores cannot be named and we don't know
// in advance what will be the name
await waitForStatus(page, baseBackupName + '-1', 'Succeeded', 120000);
});

test(`Check data after restore [${db} size ${size}]`, async () => {
// Validate the data in the t1 and t2
const t1Data = await queryTestDB(clusterName, namespace, 't1');
expect(t1Data.trim()).toBe('[ { a: 1 }, { a: 2 }, { a: 3 } ]');

const t2Data = await queryTestDB(clusterName, namespace, 't2');
expect(t2Data.trim()).toBe('[ { a: 1 }, { a: 2 }, { a: 3 } ]');
Comment on lines +304 to +309
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this into test.step with the description which is now in the comment.


// Validate sharding
const shardingStatus = await queryPSMDB(
clusterName,
namespace,
'admin',
'sh.status();'
);
expect(shardingStatus).toContain('test.t1');
expect(shardingStatus).toContain('test.t2');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this into test.step with the description which is now in the comment.

});

test(`Delete restore [${db} size ${size}]`, async ({ page }) => {
await gotoDbClusterRestores(page, clusterName);
await findRowAndClickActions(page, baseBackupName + '-1', 'Delete');
await expect(page.getByLabel('Delete restore')).toBeVisible();
await page.getByTestId('confirm-dialog-delete').click();
await waitForDelete(page, baseBackupName + '-1', 15000);
});

test(`Delete backup [${db} size ${size}]`, async ({ page }) => {
await gotoDbClusterBackups(page, clusterName);
await findRowAndClickActions(page, baseBackupName + '-1', 'Delete');
await expect(page.getByLabel('Delete backup')).toBeVisible();
await page.getByTestId('form-dialog-delete').click();
await waitForDelete(page, baseBackupName + '-1', 30000);
});

test(`Delete cluster [${db} size ${size}]`, async ({ page }) => {
await deleteDbCluster(page, clusterName);
await waitForStatus(page, clusterName, 'Deleting', 15000);
await waitForDelete(page, clusterName, 240000);
});
}
);
Loading
Loading