Skip to content

Commit 67a4088

Browse files
committed
fix: exponential backoff and more robust deletion
1 parent ece2567 commit 67a4088

File tree

4 files changed

+66
-39
lines changed

4 files changed

+66
-39
lines changed

integration_test/cloudbuild-v1.yaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ steps:
3030
npm ci
3131
# Install firebase-tools globally
3232
npm install -g firebase-tools
33-
# Install gcloud CLI for Cloud Tasks cleanup
34-
curl https://sdk.cloud.google.com | bash
35-
export PATH="$$PATH:/root/google-cloud-sdk/bin"
36-
# Source the gcloud environment
37-
source /root/google-cloud-sdk/path.bash.inc
33+
# gcloud is pre-installed in Cloud Build, no need to install
3834
# Verify tools are installed
3935
firebase --version
4036
gcloud --version

integration_test/cloudbuild-v2.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ steps:
1717
- |
1818
# Step 1: Build and pack the firebase-functions SDK from source
1919
echo "Building firebase-functions SDK from source..."
20+
pwd
21+
ls -la
2022
npm ci
2123
npm run build
2224
npm pack
@@ -30,14 +32,13 @@ steps:
3032
npm ci
3133
# Install firebase-tools globally
3234
npm install -g firebase-tools
33-
# Install gcloud CLI for Cloud Tasks cleanup
34-
curl https://sdk.cloud.google.com | bash
35-
export PATH="$$PATH:/root/google-cloud-sdk/bin"
36-
# Source the gcloud environment
37-
source /root/google-cloud-sdk/path.bash.inc
35+
# gcloud is pre-installed in Cloud Build, just set the project
36+
gcloud config set project functions-integration-tests-v2
3837
# Verify tools are installed
3938
firebase --version
4039
gcloud --version
40+
# Verify gcloud project is set correctly
41+
gcloud config get-value project
4142
# V2 tests use functions-integration-tests-v2 project
4243
echo "Running V2 tests on project: functions-integration-tests-v2"
4344
# Use Application Default Credentials (Cloud Build service account)

integration_test/scripts/run-tests.js

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ const SA_JSON_PATH = join(ROOT_DIR, "sa.json");
2828

2929
// Default configurations
3030
const DEFAULT_REGION = "us-central1";
31-
const MAX_DEPLOY_ATTEMPTS = 3;
32-
const DEFAULT_BASE_DELAY = 5000; // Base delay in ms (5 seconds)
33-
const DEFAULT_MAX_DELAY = 60000; // Max delay in ms (60 seconds)
31+
const MAX_DEPLOY_ATTEMPTS = 5;
32+
const DEFAULT_BASE_DELAY = 30000; // Base delay in ms (30 seconds)
33+
const DEFAULT_MAX_DELAY = 120000; // Max delay in ms (120 seconds/2 minutes)
3434

3535
class TestRunner {
3636
constructor(options = {}) {
@@ -553,25 +553,54 @@ class TestRunner {
553553
}
554554

555555
for (const functionName of functions) {
556+
let deleted = false;
557+
558+
// Try Firebase CLI first
556559
try {
557560
await this.exec(
558561
`firebase functions:delete ${functionName} --project ${metadata.projectId} --region ${
559562
metadata.region || DEFAULT_REGION
560563
} --force`,
561564
{ silent: true }
562565
);
563-
this.log(` Deleted function: ${functionName}`);
566+
this.log(` ✅ Deleted function via Firebase CLI: ${functionName}`, "success");
567+
deleted = true;
564568
} catch (error) {
565-
// Try gcloud as fallback
566-
try {
567-
await this.exec(
568-
`gcloud functions delete ${functionName} --region=${
569-
metadata.region || DEFAULT_REGION
570-
} --project=${metadata.projectId} --quiet`,
571-
{ silent: true }
572-
);
573-
} catch (e) {
574-
// Ignore cleanup errors
569+
this.log(` ⚠️ Firebase CLI delete failed for ${functionName}: ${error.message}`, "warn");
570+
571+
// For v2 functions, if Firebase fails (likely due to missing scheduler job),
572+
// try to delete the Cloud Run service directly
573+
if (metadata.projectId === "functions-integration-tests-v2") {
574+
this.log(` Attempting Cloud Run service deletion for v2 function...`, "warn");
575+
try {
576+
await this.exec(
577+
`gcloud run services delete ${functionName} --region=${
578+
metadata.region || DEFAULT_REGION
579+
} --project=${metadata.projectId} --quiet`,
580+
{ silent: true }
581+
);
582+
this.log(` ✅ Deleted function as Cloud Run service: ${functionName}`, "success");
583+
deleted = true;
584+
} catch (runError) {
585+
this.log(` ⚠️ Cloud Run delete failed: ${runError.message}`, "warn");
586+
}
587+
}
588+
589+
// If still not deleted, try gcloud functions delete as last resort
590+
if (!deleted) {
591+
try {
592+
await this.exec(
593+
`gcloud functions delete ${functionName} --region=${
594+
metadata.region || DEFAULT_REGION
595+
} --project=${metadata.projectId} --quiet`,
596+
{ silent: true }
597+
);
598+
this.log(` ✅ Deleted function via gcloud: ${functionName}`, "success");
599+
deleted = true;
600+
} catch (e) {
601+
this.log(` ❌ Failed to delete function ${functionName} via any method`, "error");
602+
this.log(` Last error: ${e.message}`, "error");
603+
}
575604
}
576605
}
577606
}
@@ -705,15 +734,14 @@ class TestRunner {
705734
this.log("🧹 Checking for existing test functions...", "warn");
706735

707736
// Determine which project(s) to clean up based on the filter
708-
const { getProjectIds } = await import("./generate.js");
709-
const projectIds = getProjectIds();
737+
const projectIds = this.getProjectIds();
710738

711739
let projectsToCheck = [];
712740
if (this.filter.includes("v1") || (!this.filter && !this.exclude)) {
713-
projectsToCheck.push(projectIds.v1);
741+
projectsToCheck.push(projectIds.v1ProjectId);
714742
}
715743
if (this.filter.includes("v2") || (!this.filter && !this.exclude)) {
716-
projectsToCheck.push(projectIds.v2);
744+
projectsToCheck.push(projectIds.v2ProjectId);
717745
}
718746

719747
// If no filter, check both projects
@@ -736,12 +764,14 @@ class TestRunner {
736764

737765
for (const line of lines) {
738766
// Look for table rows with function names (containing │)
739-
if (line.includes("│") && line.includes("Test")) {
767+
// Skip header rows and empty lines
768+
if (line.includes("│") && !line.includes("Function") && !line.includes("────")) {
740769
const parts = line.split("│");
741770
if (parts.length >= 2) {
742771
const functionName = parts[1].trim();
743-
// Check if it's a test function (contains Test + test run ID pattern)
744-
if (functionName.match(/Test.*t[a-z0-9]{7,10}/)) {
772+
// Add ALL functions for cleanup (not just test functions)
773+
// This ensures a clean slate for testing
774+
if (functionName && functionName.length > 0) {
745775
testFunctions.push(functionName);
746776
}
747777
}
@@ -750,7 +780,7 @@ class TestRunner {
750780

751781
if (testFunctions.length > 0) {
752782
this.log(
753-
` Found ${testFunctions.length} test function(s) in ${projectId}. Cleaning up...`,
783+
` Found ${testFunctions.length} function(s) in ${projectId}. Cleaning up ALL functions...`,
754784
"warn"
755785
);
756786

@@ -789,7 +819,7 @@ class TestRunner {
789819
}
790820
}
791821
} else {
792-
this.log(` ✅ No test functions found in ${projectId}`, "success");
822+
this.log(` ✅ No functions found in ${projectId}`, "success");
793823
}
794824
} catch (e) {
795825
this.log(` ⚠️ Could not check functions in ${projectId}: ${e.message}`, "warn");
@@ -814,15 +844,14 @@ class TestRunner {
814844
this.log(" Checking for orphaned Cloud Tasks queues...", "warn");
815845

816846
// Determine which project(s) to clean up based on the filter
817-
const { getProjectIds } = await import("./generate.js");
818-
const projectIds = getProjectIds();
847+
const projectIds = this.getProjectIds();
819848

820849
let projectsToCheck = [];
821850
if (this.filter.includes("v1") || (!this.filter && !this.exclude)) {
822-
projectsToCheck.push(projectIds.v1);
851+
projectsToCheck.push(projectIds.v1ProjectId);
823852
}
824853
if (this.filter.includes("v2") || (!this.filter && !this.exclude)) {
825-
projectsToCheck.push(projectIds.v2);
854+
projectsToCheck.push(projectIds.v2ProjectId);
826855
}
827856

828857
// If no filter, check both projects
@@ -954,7 +983,8 @@ class TestRunner {
954983
}
955984

956985
// Run each suite
957-
for (const suite of suiteNames) {
986+
for (let i = 0; i < suiteNames.length; i++) {
987+
const suite = suiteNames[i];
958988
await this.runSuite(suite);
959989
this.log("");
960990
}

integration_test/tsconfig.test.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"extends": "./tsconfig.json",
33
"compilerOptions": {
44
"module": "ES2020",
5-
"moduleResolution": "Bundler",
5+
"moduleResolution": "node",
66
"resolveJsonModule": true,
77
"types": ["jest", "node"]
88
},

0 commit comments

Comments
 (0)