diff --git a/tools/integration_tests/dentry_cache/notifier_test.go b/tools/integration_tests/dentry_cache/notifier_test.go index 5dcca7abccf..6e8e556c851 100644 --- a/tools/integration_tests/dentry_cache/notifier_test.go +++ b/tools/integration_tests/dentry_cache/notifier_test.go @@ -72,7 +72,7 @@ func (s *notifierTest) TestWriteFileWithDentryCacheEnabled() { err = operations.WriteFile(filePath, "ShouldNotWrite") // First Write File attempt should fail because file has been clobbered. - operations.ValidateESTALEError(s.T(), err) + operations.ValidateESTALEOrEIOError(s.T(), err) // Second Write File attempt. err = operations.WriteFile(filePath, "ShouldWrite") // The notifier is triggered after the first write failure, invalidating the kernel cache entry. @@ -97,7 +97,7 @@ func (s *notifierTest) TestReadFileWithDentryCacheEnabled() { // First Read File attempt. _, err = operations.ReadFile(filePath) // First Read File attempt should fail because file has been clobbered. - operations.ValidateESTALEError(s.T(), err) + operations.ValidateESTALEOrEIOError(s.T(), err) // Second Read File attempt. _, err = operations.ReadFile(filePath) // The notifier is triggered after the first read failure, invalidating the kernel cache entry. @@ -119,7 +119,7 @@ func (s *notifierTest) TestDeleteFileWithDentryCacheEnabled() { // Read File to call the notifier to invalidate entry. _, err = operations.ReadFile(filePath) // The notifier is triggered after the first read failure, invalidating the kernel cache entry. - operations.ValidateESTALEError(s.T(), err) + operations.ValidateESTALEOrEIOError(s.T(), err) // Stat again, it should give error as entry does not exist. _, err = os.Stat(filePath) diff --git a/tools/integration_tests/managed_folders/managed_folders_test.go b/tools/integration_tests/managed_folders/managed_folders_test.go index 0508fcfdce9..0896279a976 100644 --- a/tools/integration_tests/managed_folders/managed_folders_test.go +++ b/tools/integration_tests/managed_folders/managed_folders_test.go @@ -88,6 +88,13 @@ func TestMain(m *testing.M) { } testEnv.ctx = context.Background() + + // Check if the GCP project is allowlisted before doing setup or initializing clients. + if !creds_tests.IsAllowlistedProject(testEnv.ctx) { + log.Printf("The active GCP project is not one of the allowlisted projects. Skipping managed folders tests.") + os.Exit(0) + } + testEnv.bucketType = setup.TestEnvironment(testEnv.ctx, &cfg.ManagedFolders[0]) testEnv.cfg = &cfg.ManagedFolders[0] diff --git a/tools/integration_tests/mount_timeout/mount_access_test.go b/tools/integration_tests/mount_timeout/mount_access_test.go index ed8b8a80688..16f64cb0481 100644 --- a/tools/integration_tests/mount_timeout/mount_access_test.go +++ b/tools/integration_tests/mount_timeout/mount_access_test.go @@ -82,6 +82,9 @@ func (testSuite *MountAccessTest) mountWithKeyFile(bucketName, keyFile string) ( } func (testSuite *MountAccessTest) TestMountingWithMinimalAccessSucceeds() { + if !creds_tests.IsAllowlistedProject(gCtx) { + testSuite.T().Skip("Skipping credentials test on non-allowlisted project.") + } if !client.CheckBucketAccess(gCtx, gStorageClient, testBucket) { testSuite.T().Skipf("Skipping test as bucket %q is not accessible", testBucket) } diff --git a/tools/integration_tests/requester_pays_bucket/setup_test.go b/tools/integration_tests/requester_pays_bucket/setup_test.go index 8fe4f3e9078..03175020319 100644 --- a/tools/integration_tests/requester_pays_bucket/setup_test.go +++ b/tools/integration_tests/requester_pays_bucket/setup_test.go @@ -99,6 +99,10 @@ func TestMain(m *testing.M) { // When not running in GKE environment. if cfg.RequesterPaysBucket[0].GKEMountedDirectory == "" { + if !creds_tests.IsAllowlistedProject(testEnv.ctx) { + log.Printf("The active GCP project is not one of the allowlisted projects. Skipping requester pays bucket tests.") + os.Exit(0) + } // Replace --billing-project= placeholder in flags with the default billing project. for i := range cfg.RequesterPaysBucket[0].Configs { for j, flag := range cfg.RequesterPaysBucket[0].Configs[i].Flags { diff --git a/tools/integration_tests/util/creds_tests/creds.go b/tools/integration_tests/util/creds_tests/creds.go index 50c7014b937..c9d26e3c008 100644 --- a/tools/integration_tests/util/creds_tests/creds.go +++ b/tools/integration_tests/util/creds_tests/creds.go @@ -23,6 +23,7 @@ import ( "os" "slices" "strings" + "sync" "testing" "time" @@ -39,22 +40,47 @@ import ( const NameOfServiceAccount = "creds-integration-tests" const CredentialsSecretName = "gcsfuse-integration-tests" -var WhitelistedGcpProjects = []string{"gcs-fuse-test", "gcs-fuse-test-ml"} +var AllowlistedGcpProjects = []string{"gcs-fuse-test", "gcs-fuse-test-ml"} + +var ( + cachedProjectID string + projectIDOnce sync.Once +) + +func getCachedProjectID(ctx context.Context) (string, error) { + var err error + projectIDOnce.Do(func() { + cachedProjectID, err = metadata.ProjectIDWithContext(ctx) + }) + return cachedProjectID, err +} + +func IsAllowlistedProject(ctx context.Context) bool { + id, err := getCachedProjectID(ctx) + if err != nil { + log.Printf("Error in fetching project id: %v", err) + return false + } + if strings.Contains(id, "cloudtop") { + return true + } + return slices.Contains(AllowlistedGcpProjects, id) +} func projectID(ctx context.Context) string { // Fetching project-id to get service account id. - id, err := metadata.ProjectIDWithContext(ctx) + id, err := getCachedProjectID(ctx) if err != nil { setup.LogAndExit(fmt.Sprintf("Error in fetching project id: %v", err)) } if strings.Contains(id, "cloudtop") { - // In cloudtop environments, well known path is used for auth. So explicitly set the project as whitelisted. - id = WhitelistedGcpProjects[0] + // In cloudtop environments, well known path is used for auth. So explicitly set the project as allowlisted. + id = AllowlistedGcpProjects[0] } - // return if active GCP project is not in whitelisted gcp projects - if !slices.Contains(WhitelistedGcpProjects, id) { - log.Printf("The active GCP project is not one of: %s. So the credentials test will not run.", strings.Join(WhitelistedGcpProjects, ", ")) + // return if active GCP project is not in allowlisted gcp projects + if !slices.Contains(AllowlistedGcpProjects, id) { + log.Printf("The active GCP project is not one of: %s. So the credentials test will not run.", strings.Join(AllowlistedGcpProjects, ", ")) } return id } @@ -161,6 +187,10 @@ func RevokeCustomRoleFromServiceAccountOnBucket(ctx context.Context, storageClie } func RunTestsForDifferentAuthMethods(ctx context.Context, cfg *test_suite.TestConfig, storageClient *storage.Client, testFlagSet [][]string, permission string, m *testing.M) (successCode int) { + if !IsAllowlistedProject(ctx) { + log.Printf("The active GCP project is not one of: %s. So the credentials test will not run.", strings.Join(AllowlistedGcpProjects, ", ")) + return 0 + } serviceAccount, localKeyFilePath := CreateCredentials(ctx) defer func() { if err := os.Remove(localKeyFilePath); err != nil { diff --git a/tools/integration_tests/util/operations/file_operations.go b/tools/integration_tests/util/operations/file_operations.go index 3c9ad02c26b..16e00667b6b 100644 --- a/tools/integration_tests/util/operations/file_operations.go +++ b/tools/integration_tests/util/operations/file_operations.go @@ -109,7 +109,7 @@ func CopyFileAllowOverwrite(srcFileName, newFileName string) (err error) { func ReadFile(filePath string) (content []byte, err error) { content, err = os.ReadFile(filePath) if err != nil { - err = fmt.Errorf("ReadFile: %v", err) + err = fmt.Errorf("ReadFile: %w", err) return } return @@ -140,7 +140,7 @@ func RenameFile(fileName string, newFileName string) (err error) { func WriteFileInAppendMode(fileName string, content string) (err error) { f, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|syscall.O_DIRECT, FilePermission_0600) if err != nil { - err = fmt.Errorf("open file for append: %v", err) + err = fmt.Errorf("open file for append: %w", err) return } @@ -155,7 +155,7 @@ func WriteFileInAppendMode(fileName string, content string) (err error) { func WriteFile(fileName string, content string) (err error) { f, err := os.OpenFile(fileName, os.O_RDWR|syscall.O_DIRECT, FilePermission_0600) if err != nil { - err = fmt.Errorf("open file for write at start: %v", err) + err = fmt.Errorf("open file for write at start: %w", err) return } diff --git a/tools/integration_tests/util/operations/validation_helper.go b/tools/integration_tests/util/operations/validation_helper.go index 25f18fabca8..c16d02c491b 100644 --- a/tools/integration_tests/util/operations/validation_helper.go +++ b/tools/integration_tests/util/operations/validation_helper.go @@ -52,14 +52,29 @@ func ValidateESTALEError(t *testing.T, err error) { t.Helper() require.Error(t, err) - assert.Regexp(t, syscall.ESTALE.Error(), err.Error()) + if !errors.Is(err, syscall.ESTALE) { + t.Fatalf("Expected error to be %q (ESTALE). Got: %v", syscall.ESTALE, err) + } +} + +func ValidateESTALEOrEIOError(t *testing.T, err error) { + t.Helper() + + require.Error(t, err) + // FUSE kernel driver can translate ESTALE to EIO (input/output error) on some operations/kernels. + // So we accept both "stale file handle" (ESTALE) and "input/output error" (EIO). + if !errors.Is(err, syscall.ESTALE) && !errors.Is(err, syscall.EIO) { + t.Fatalf("Expected error to be %q (ESTALE) or %q (EIO). Got: %v", syscall.ESTALE, syscall.EIO, err) + } } func ValidateEIOError(t *testing.T, err error) { t.Helper() require.Error(t, err) - assert.Regexp(t, syscall.EIO.Error(), err.Error()) + if !errors.Is(err, syscall.EIO) { + t.Fatalf("Expected error to be %q (EIO). Got: %v", syscall.EIO, err) + } } func CheckErrorForReadOnlyFileSystem(t *testing.T, err error) {