@@ -28,9 +28,9 @@ const SA_JSON_PATH = join(ROOT_DIR, "sa.json");
28
28
29
29
// Default configurations
30
30
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 )
34
34
35
35
class TestRunner {
36
36
constructor ( options = { } ) {
@@ -553,25 +553,54 @@ class TestRunner {
553
553
}
554
554
555
555
for ( const functionName of functions ) {
556
+ let deleted = false ;
557
+
558
+ // Try Firebase CLI first
556
559
try {
557
560
await this . exec (
558
561
`firebase functions:delete ${ functionName } --project ${ metadata . projectId } --region ${
559
562
metadata . region || DEFAULT_REGION
560
563
} --force`,
561
564
{ silent : true }
562
565
) ;
563
- this . log ( ` Deleted function: ${ functionName } ` ) ;
566
+ this . log ( ` ✅ Deleted function via Firebase CLI: ${ functionName } ` , "success" ) ;
567
+ deleted = true ;
564
568
} 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
+ }
575
604
}
576
605
}
577
606
}
@@ -705,15 +734,14 @@ class TestRunner {
705
734
this . log ( "🧹 Checking for existing test functions..." , "warn" ) ;
706
735
707
736
// 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 ( ) ;
710
738
711
739
let projectsToCheck = [ ] ;
712
740
if ( this . filter . includes ( "v1" ) || ( ! this . filter && ! this . exclude ) ) {
713
- projectsToCheck . push ( projectIds . v1 ) ;
741
+ projectsToCheck . push ( projectIds . v1ProjectId ) ;
714
742
}
715
743
if ( this . filter . includes ( "v2" ) || ( ! this . filter && ! this . exclude ) ) {
716
- projectsToCheck . push ( projectIds . v2 ) ;
744
+ projectsToCheck . push ( projectIds . v2ProjectId ) ;
717
745
}
718
746
719
747
// If no filter, check both projects
@@ -736,12 +764,14 @@ class TestRunner {
736
764
737
765
for ( const line of lines ) {
738
766
// 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 ( "────" ) ) {
740
769
const parts = line . split ( "│" ) ;
741
770
if ( parts . length >= 2 ) {
742
771
const functionName = parts [ 1 ] . trim ( ) ;
743
- // Check if it's a test function (contains Test + test run ID pattern)
744
- if ( functionName . match ( / T e s t .* t [ a - z 0 - 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 ) {
745
775
testFunctions . push ( functionName ) ;
746
776
}
747
777
}
@@ -750,7 +780,7 @@ class TestRunner {
750
780
751
781
if ( testFunctions . length > 0 ) {
752
782
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 ...` ,
754
784
"warn"
755
785
) ;
756
786
@@ -789,7 +819,7 @@ class TestRunner {
789
819
}
790
820
}
791
821
} else {
792
- this . log ( ` ✅ No test functions found in ${ projectId } ` , "success" ) ;
822
+ this . log ( ` ✅ No functions found in ${ projectId } ` , "success" ) ;
793
823
}
794
824
} catch ( e ) {
795
825
this . log ( ` ⚠️ Could not check functions in ${ projectId } : ${ e . message } ` , "warn" ) ;
@@ -814,15 +844,14 @@ class TestRunner {
814
844
this . log ( " Checking for orphaned Cloud Tasks queues..." , "warn" ) ;
815
845
816
846
// 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 ( ) ;
819
848
820
849
let projectsToCheck = [ ] ;
821
850
if ( this . filter . includes ( "v1" ) || ( ! this . filter && ! this . exclude ) ) {
822
- projectsToCheck . push ( projectIds . v1 ) ;
851
+ projectsToCheck . push ( projectIds . v1ProjectId ) ;
823
852
}
824
853
if ( this . filter . includes ( "v2" ) || ( ! this . filter && ! this . exclude ) ) {
825
- projectsToCheck . push ( projectIds . v2 ) ;
854
+ projectsToCheck . push ( projectIds . v2ProjectId ) ;
826
855
}
827
856
828
857
// If no filter, check both projects
@@ -954,7 +983,8 @@ class TestRunner {
954
983
}
955
984
956
985
// Run each suite
957
- for ( const suite of suiteNames ) {
986
+ for ( let i = 0 ; i < suiteNames . length ; i ++ ) {
987
+ const suite = suiteNames [ i ] ;
958
988
await this . runSuite ( suite ) ;
959
989
this . log ( "" ) ;
960
990
}
0 commit comments