Fix playwright tests (#2325)

* Fix cleanupDBs.js: use async iteration for Azure SDK paged results

* update node version

* fix cleanup script to use new Cosmos SDK APIs correctly

* get rid of global crypto

* fix flakiness

* revert DE pipeline to use Node 18

* nit

---------

Co-authored-by: Asier Isayas <aisayas@microsoft.com>
This commit is contained in:
asier-isayas
2026-04-03 14:34:10 -04:00
committed by GitHub
parent 2ba58cd1a5
commit aa70cf994a
3 changed files with 39 additions and 31 deletions

View File

@@ -22,18 +22,18 @@ jobs:
env: env:
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: "Az CLI login" - name: "Az CLI login"
uses: azure/login@v1 uses: azure/login@v2
with: with:
client-id: ${{ secrets.E2E_TESTS_CLIENT_ID }} client-id: ${{ secrets.E2E_TESTS_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Use Node.js 18.x - name: Use Node.js 20.x
uses: actions/setup-node@v1 uses: actions/setup-node@v4
with: with:
node-version: 18.x node-version: 20.x
- run: npm ci - run: npm ci
- run: node utils/cleanupDBs.js - run: node utils/cleanupDBs.js

View File

@@ -24,6 +24,14 @@ test.describe("Vector Policy under Scale & Settings", () => {
await vectorPolicyTab.click(); await vectorPolicyTab.click();
}); });
test.afterEach("Clear vector policies", async () => {
const { resource: containerDef } = await context.container.read();
if (containerDef.vectorEmbeddingPolicy?.vectorEmbeddings?.length) {
containerDef.vectorEmbeddingPolicy.vectorEmbeddings = [];
await context.container.replace(containerDef);
}
});
test.afterAll("Delete Test Database", async () => { test.afterAll("Delete Test Database", async () => {
await context?.dispose(); await context?.dispose();
}); });

View File

@@ -18,65 +18,66 @@ function friendlyTime(date) {
async function main() { async function main() {
const credentials = new AzureCliCredential(); const credentials = new AzureCliCredential();
const client = new CosmosDBManagementClient(credentials, subscriptionId); const client = new CosmosDBManagementClient(credentials, subscriptionId);
const accounts = await client.databaseAccounts.list(resourceGroupName); const accounts = client.databaseAccounts.listByResourceGroup(resourceGroupName);
for (const account of accounts) { for await (const account of accounts) {
if (account.name.endsWith("-readonly")) { if (account.name.endsWith("-readonly")) {
console.log(`SKIPPED: ${account.name}`); console.log(`SKIPPED: ${account.name}`);
continue; continue;
} }
if (account.kind === "MongoDB") { if (account.kind === "MongoDB") {
const mongoDatabases = await client.mongoDBResources.listMongoDBDatabases(resourceGroupName, account.name); const mongoDatabases = client.mongoDBResources.listMongoDBDatabases(resourceGroupName, account.name);
for (const database of mongoDatabases) { for await (const database of mongoDatabases) {
// Unfortunately Mongo does not provide a timestamp in ARM. There is no way to tell how old the DB is other thn encoding it in the ID :( // Unfortunately Mongo does not provide a timestamp in ARM. There is no way to tell how old the DB is other thn encoding it in the ID :(
const timestamp = Number(database.name.split("_").pop()); const timestamp = Number(database.name.split("_").pop());
if (timestamp && timestamp < thirtyMinutesAgo) { if (timestamp && timestamp < thirtyMinutesAgo) {
await client.mongoDBResources.deleteMongoDBDatabase(resourceGroupName, account.name, database.name); await client.mongoDBResources.beginDeleteMongoDBDatabaseAndWait(resourceGroupName, account.name, database.name);
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} else { } else {
console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} }
} }
} else if (account.capabilities.find((c) => c.name === "EnableCassandra")) { } else if (account.capabilities.find((c) => c.name === "EnableCassandra")) {
const cassandraDatabases = await client.cassandraResources.listCassandraKeyspaces( const cassandraDatabases = client.cassandraResources.listCassandraKeyspaces(
resourceGroupName, resourceGroupName,
account.name, account.name,
); );
for (const database of cassandraDatabases) { for await (const database of cassandraDatabases) {
const timestamp = Number(database.resource._ts) * 1000; const timestamp = Number(database.resource.ts) * 1000;
if (timestamp && timestamp < thirtyMinutesAgo) { if (timestamp && timestamp < thirtyMinutesAgo) {
await client.cassandraResources.deleteCassandraKeyspace(resourceGroupName, account.name, database.name); await client.cassandraResources.beginDeleteCassandraKeyspaceAndWait(resourceGroupName, account.name, database.name);
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} else { } else {
console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} }
} }
} else if (account.capabilities.find((c) => c.name === "EnableTable")) { } else if (account.capabilities.find((c) => c.name === "EnableTable")) {
const tablesDatabase = await client.tableResources.listTables(resourceGroupName, account.name); const tablesDatabase = client.tableResources.listTables(resourceGroupName, account.name);
for (const database of tablesDatabase) { for await (const database of tablesDatabase) {
const timestamp = Number(database.resource._ts) * 1000; const timestamp = Number(database.resource.ts) * 1000;
if (timestamp && timestamp < thirtyMinutesAgo) { if (timestamp && timestamp < thirtyMinutesAgo) {
await client.tableResources.deleteTable(resourceGroupName, account.name, database.name); await client.tableResources.beginDeleteTableAndWait(resourceGroupName, account.name, database.name);
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} else { } else {
console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} }
} }
} else if (account.capabilities.find((c) => c.name === "EnableGremlin")) { } else if (account.capabilities.find((c) => c.name === "EnableGremlin")) {
const graphDatabases = await client.gremlinResources.listGremlinDatabases(resourceGroupName, account.name); const graphDatabases = client.gremlinResources.listGremlinDatabases(resourceGroupName, account.name);
for (const database of graphDatabases) { for await (const database of graphDatabases) {
const timestamp = Number(database.resource._ts) * 1000; const timestamp = Number(database.resource.ts) * 1000;
if (timestamp && timestamp < thirtyMinutesAgo) { if (timestamp && timestamp < thirtyMinutesAgo) {
await client.gremlinResources.deleteGremlinDatabase(resourceGroupName, account.name, database.name); await client.gremlinResources.beginDeleteGremlinDatabaseAndWait(resourceGroupName, account.name, database.name);
console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`DELETED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} else { } else {
console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`SKIPPED: ${account.name} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} }
} }
} else if (account.kind === "GlobalDocumentDB") { } else if (account.kind === "GlobalDocumentDB") {
const sqlDatabases = await client.sqlResources.listSqlDatabases(resourceGroupName, account.name); const sqlDatabases = client.sqlResources.listSqlDatabases(resourceGroupName, account.name);
const sqlDatabasesToDelete = sqlDatabases.map(async (database) => { const sqlDatabasesToDelete = [];
await deleteWithRetry(client, database, account.name); for await (const database of sqlDatabases) {
}); sqlDatabasesToDelete.push(deleteWithRetry(client, database, account.name));
}
await Promise.all(sqlDatabasesToDelete); await Promise.all(sqlDatabasesToDelete);
} }
} }
@@ -90,9 +91,9 @@ async function deleteWithRetry(client, database, accountName) {
while (attempt < maxRetries) { while (attempt < maxRetries) {
try { try {
const timestamp = Number(database.resource._ts) * 1000; const timestamp = Number(database.resource.ts) * 1000;
if (timestamp && timestamp < thirtyMinutesAgo) { if (timestamp && timestamp < thirtyMinutesAgo) {
await client.sqlResources.deleteSqlDatabase(resourceGroupName, accountName, database.name); await client.sqlResources.beginDeleteSqlDatabaseAndWait(resourceGroupName, accountName, database.name);
console.log(`DELETED: ${accountName} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`DELETED: ${accountName} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
} else { } else {
console.log(`SKIPPED: ${accountName} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`); console.log(`SKIPPED: ${accountName} | ${database.name} | Age: ${friendlyTime(Date.now() - timestamp)}`);
@@ -126,7 +127,6 @@ main()
process.exit(0); process.exit(0);
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.error(err);
console.log("Cleanup failed! Exiting with success. Cleanup should always fail safe."); process.exit(1);
process.exit(0);
}); });