From 0087b24f4c190b30f5b892dde96ec82cc0e63a1e Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Tue, 23 Apr 2024 06:49:21 +0000 Subject: [PATCH 01/16] implementation for ignoring interrupts --- internal/fs/fs.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 2be5d32df5..74279a8f47 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -15,6 +15,7 @@ package fs import ( + "context" "errors" "fmt" "io" @@ -43,7 +44,6 @@ import ( "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" "github.com/jacobsa/timeutil" - "golang.org/x/net/context" ) type ServerConfig struct { @@ -124,6 +124,9 @@ type ServerConfig struct { // File chunk size to read from GCS in one call. Specified in MB. SequentialReadSizeMb int32 + // Allows ignoring interrupts. + IgnoreInterrupts bool + // MountConfig has all the config specified by the user using configFile flag. MountConfig *config.MountConfig } @@ -176,6 +179,7 @@ func NewFileSystem( inodeAttributeCacheTTL: cfg.InodeAttributeCacheTTL, dirTypeCacheTTL: cfg.DirTypeCacheTTL, renameDirLimit: cfg.RenameDirLimit, + ignoreInterrupts: cfg.IgnoreInterrupts, sequentialReadSizeMb: cfg.SequentialReadSizeMb, uid: cfg.Uid, gid: cfg.Gid, @@ -342,6 +346,7 @@ type fileSystem struct { inodeAttributeCacheTTL time.Duration dirTypeCacheTTL time.Duration renameDirLimit int64 + ignoreInterrupts bool sequentialReadSizeMb int32 // The user and group owning everything in the file system. @@ -1313,6 +1318,10 @@ func (fs *fileSystem) StatFS( func (fs *fileSystem) LookUpInode( ctx context.Context, op *fuseops.LookUpInodeOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on LookUpInode. + ctx = context.WithoutCancel(ctx) + } // Find the parent directory in question. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1342,6 +1351,10 @@ func (fs *fileSystem) LookUpInode( func (fs *fileSystem) GetInodeAttributes( ctx context.Context, op *fuseops.GetInodeAttributesOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on GetInodeAttributes. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1363,6 +1376,10 @@ func (fs *fileSystem) GetInodeAttributes( func (fs *fileSystem) SetInodeAttributes( ctx context.Context, op *fuseops.SetInodeAttributesOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on SetInodeAttributes. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1406,6 +1423,10 @@ func (fs *fileSystem) SetInodeAttributes( func (fs *fileSystem) ForgetInode( ctx context.Context, op *fuseops.ForgetInodeOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on ForgetInode. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1422,6 +1443,10 @@ func (fs *fileSystem) ForgetInode( func (fs *fileSystem) MkDir( ctx context.Context, op *fuseops.MkDirOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on MkDir. + ctx = context.WithoutCancel(ctx) + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1474,6 +1499,10 @@ func (fs *fileSystem) MkDir( func (fs *fileSystem) MkNode( ctx context.Context, op *fuseops.MkNodeOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on MkNode. + ctx = context.WithoutCancel(ctx) + } if (op.Mode & (iofs.ModeNamedPipe | iofs.ModeSocket)) != 0 { return syscall.ENOTSUP } @@ -1597,6 +1626,10 @@ func (fs *fileSystem) createLocalFile( func (fs *fileSystem) CreateFile( ctx context.Context, op *fuseops.CreateFileOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on CreateFile. + ctx = context.WithoutCancel(ctx) + } // Create the child. var child inode.Inode if fs.mountConfig.CreateEmptyFile { @@ -1639,6 +1672,10 @@ func (fs *fileSystem) CreateFile( func (fs *fileSystem) CreateSymlink( ctx context.Context, op *fuseops.CreateSymlinkOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on CreateSymlink. + ctx = context.WithoutCancel(ctx) + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1702,6 +1739,10 @@ func (fs *fileSystem) RmDir( ctx context.Context, op *fuseops.RmDirOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on RmDir. + ctx = context.WithoutCancel(ctx) + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1797,6 +1838,10 @@ func (fs *fileSystem) RmDir( func (fs *fileSystem) Rename( ctx context.Context, op *fuseops.RenameOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on Rename. + ctx = context.WithoutCancel(ctx) + } // Find the old and new parents. fs.mu.Lock() oldParent := fs.dirInodeOrDie(op.OldParent) @@ -2009,6 +2054,10 @@ func (fs *fileSystem) renameDir( func (fs *fileSystem) Unlink( ctx context.Context, op *fuseops.UnlinkOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on Unlink. + ctx = context.WithoutCancel(ctx) + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -2077,6 +2126,10 @@ func (fs *fileSystem) OpenDir( func (fs *fileSystem) ReadDir( ctx context.Context, op *fuseops.ReadDirOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on ReadDir. + ctx = context.WithoutCancel(ctx) + } // Find the handle. fs.mu.Lock() dh := fs.handles[op.Handle].(*handle.DirHandle) @@ -2142,6 +2195,10 @@ func (fs *fileSystem) OpenFile( func (fs *fileSystem) ReadFile( ctx context.Context, op *fuseops.ReadFileOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on ReadFile. + ctx = context.WithoutCancel(ctx) + } // Save readOp in context for access in logs. ctx = context.WithValue(ctx, gcsx.ReadOp, op) @@ -2169,6 +2226,10 @@ func (fs *fileSystem) ReadFile( func (fs *fileSystem) ReadSymlink( ctx context.Context, op *fuseops.ReadSymlinkOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on ReadSymlink. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.symlinkInodeOrDie(op.Inode) @@ -2187,6 +2248,10 @@ func (fs *fileSystem) ReadSymlink( func (fs *fileSystem) WriteFile( ctx context.Context, op *fuseops.WriteFileOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on WriteFile. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.fileInodeOrDie(op.Inode) @@ -2207,6 +2272,10 @@ func (fs *fileSystem) WriteFile( func (fs *fileSystem) SyncFile( ctx context.Context, op *fuseops.SyncFileOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on SyncFile. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -2233,6 +2302,10 @@ func (fs *fileSystem) SyncFile( func (fs *fileSystem) FlushFile( ctx context.Context, op *fuseops.FlushFileOp) (err error) { + if fs.ignoreInterrupts { + // Ignore interrupts (context cancellation) on FlushFile. + ctx = context.WithoutCancel(ctx) + } // Find the inode. fs.mu.Lock() in := fs.fileInodeOrDie(op.Inode) From 30df885becc3d1dc8edf1f96f581a5c453625094 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Tue, 23 Apr 2024 08:35:50 +0000 Subject: [PATCH 02/16] refactoring and unit tests --- internal/fs/fs.go | 93 +++++++++-------------------------- internal/fs/interrupt_test.go | 50 +++++++++++++++++++ 2 files changed, 74 insertions(+), 69 deletions(-) create mode 100644 internal/fs/interrupt_test.go diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 74279a8f47..c7083d233e 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -1314,14 +1314,18 @@ func (fs *fileSystem) StatFS( return } +func (fs *fileSystem) ignoreInterruptsIfFlagIsSet(ctx context.Context) context.Context { + if fs.ignoreInterrupts { + return context.WithoutCancel(ctx) + } + return ctx +} + // LOCKS_EXCLUDED(fs.mu) func (fs *fileSystem) LookUpInode( ctx context.Context, op *fuseops.LookUpInodeOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on LookUpInode. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the parent directory in question. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1351,10 +1355,7 @@ func (fs *fileSystem) LookUpInode( func (fs *fileSystem) GetInodeAttributes( ctx context.Context, op *fuseops.GetInodeAttributesOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on GetInodeAttributes. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1376,10 +1377,7 @@ func (fs *fileSystem) GetInodeAttributes( func (fs *fileSystem) SetInodeAttributes( ctx context.Context, op *fuseops.SetInodeAttributesOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on SetInodeAttributes. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1423,10 +1421,7 @@ func (fs *fileSystem) SetInodeAttributes( func (fs *fileSystem) ForgetInode( ctx context.Context, op *fuseops.ForgetInodeOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on ForgetInode. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1443,10 +1438,7 @@ func (fs *fileSystem) ForgetInode( func (fs *fileSystem) MkDir( ctx context.Context, op *fuseops.MkDirOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on MkDir. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1499,10 +1491,7 @@ func (fs *fileSystem) MkDir( func (fs *fileSystem) MkNode( ctx context.Context, op *fuseops.MkNodeOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on MkNode. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) if (op.Mode & (iofs.ModeNamedPipe | iofs.ModeSocket)) != 0 { return syscall.ENOTSUP } @@ -1626,10 +1615,7 @@ func (fs *fileSystem) createLocalFile( func (fs *fileSystem) CreateFile( ctx context.Context, op *fuseops.CreateFileOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on CreateFile. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Create the child. var child inode.Inode if fs.mountConfig.CreateEmptyFile { @@ -1672,10 +1658,7 @@ func (fs *fileSystem) CreateFile( func (fs *fileSystem) CreateSymlink( ctx context.Context, op *fuseops.CreateSymlinkOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on CreateSymlink. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1739,10 +1722,7 @@ func (fs *fileSystem) RmDir( ctx context.Context, op *fuseops.RmDirOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on RmDir. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1838,10 +1818,7 @@ func (fs *fileSystem) RmDir( func (fs *fileSystem) Rename( ctx context.Context, op *fuseops.RenameOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on Rename. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the old and new parents. fs.mu.Lock() oldParent := fs.dirInodeOrDie(op.OldParent) @@ -2054,10 +2031,7 @@ func (fs *fileSystem) renameDir( func (fs *fileSystem) Unlink( ctx context.Context, op *fuseops.UnlinkOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on Unlink. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -2126,10 +2100,7 @@ func (fs *fileSystem) OpenDir( func (fs *fileSystem) ReadDir( ctx context.Context, op *fuseops.ReadDirOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on ReadDir. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the handle. fs.mu.Lock() dh := fs.handles[op.Handle].(*handle.DirHandle) @@ -2195,11 +2166,7 @@ func (fs *fileSystem) OpenFile( func (fs *fileSystem) ReadFile( ctx context.Context, op *fuseops.ReadFileOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on ReadFile. - ctx = context.WithoutCancel(ctx) - } - + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Save readOp in context for access in logs. ctx = context.WithValue(ctx, gcsx.ReadOp, op) @@ -2226,10 +2193,7 @@ func (fs *fileSystem) ReadFile( func (fs *fileSystem) ReadSymlink( ctx context.Context, op *fuseops.ReadSymlinkOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on ReadSymlink. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.symlinkInodeOrDie(op.Inode) @@ -2248,10 +2212,7 @@ func (fs *fileSystem) ReadSymlink( func (fs *fileSystem) WriteFile( ctx context.Context, op *fuseops.WriteFileOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on WriteFile. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.fileInodeOrDie(op.Inode) @@ -2272,10 +2233,7 @@ func (fs *fileSystem) WriteFile( func (fs *fileSystem) SyncFile( ctx context.Context, op *fuseops.SyncFileOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on SyncFile. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -2302,10 +2260,7 @@ func (fs *fileSystem) SyncFile( func (fs *fileSystem) FlushFile( ctx context.Context, op *fuseops.FlushFileOp) (err error) { - if fs.ignoreInterrupts { - // Ignore interrupts (context cancellation) on FlushFile. - ctx = context.WithoutCancel(ctx) - } + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.fileInodeOrDie(op.Inode) diff --git a/internal/fs/interrupt_test.go b/internal/fs/interrupt_test.go new file mode 100644 index 0000000000..35bb23b8b3 --- /dev/null +++ b/internal/fs/interrupt_test.go @@ -0,0 +1,50 @@ +// Copyright 2024 Google Inc. All Rights Reserved. +// +// 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. + +// A collection of tests for a file system where we do not attempt to write to +// the file system at all. Rather we set up contents in a GCS bucket out of +// band, wait for them to be available, and then read them via the file system. + +package fs + +import ( + "context" + "testing" + + "github.com/jacobsa/ogletest" +) + +var ignoreInterruptsTest = []struct { + testName string + ignoreInterrupts bool + err error +}{ + {"Ignore Interrupts", true, nil}, + {"Respect Interrupts", false, context.Canceled}, +} + +func TestIgnoreInterruptsIfFlagIsSet(t *testing.T) { + for _, tt := range ignoreInterruptsTest { + t.Run(tt.testName, func(t *testing.T) { + fs := &fileSystem{ignoreInterrupts: tt.ignoreInterrupts} + ctx, cancel := context.WithCancel(context.Background()) + + // Call the method and cancel the context + ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + cancel() + + ogletest.AssertEq(tt.err, ctx.Err()) + }) + } +} From 1b86d795b8de735a3db694acd603d14fc9cd2fa1 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Tue, 23 Apr 2024 10:02:05 +0000 Subject: [PATCH 03/16] update flag --- mount.go | 1 + 1 file changed, 1 insertion(+) diff --git a/mount.go b/mount.go index e769de31e8..da32ea06ea 100644 --- a/mount.go +++ b/mount.go @@ -120,6 +120,7 @@ be interacting with the file system.`) FilePerms: os.FileMode(flags.FileMode), DirPerms: os.FileMode(flags.DirMode), RenameDirLimit: flags.RenameDirLimit, + IgnoreInterrupts: flags.IgnoreInterrupts, SequentialReadSizeMb: flags.SequentialReadSizeMb, EnableNonexistentTypeCache: flags.EnableNonexistentTypeCache, MountConfig: mountConfig, From 5789b6d58f6f45654c23ca8c331c56bec0aba83c Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Tue, 23 Apr 2024 10:05:43 +0000 Subject: [PATCH 04/16] add integration tests --- .../interrupt/git_clone_test.go | 54 +++++++++++++++ .../interrupt/interrupt_test.go | 67 +++++++++++++++++++ .../util/operations/operations.go | 4 +- 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 tools/integration_tests/interrupt/git_clone_test.go create mode 100644 tools/integration_tests/interrupt/interrupt_test.go diff --git a/tools/integration_tests/interrupt/git_clone_test.go b/tools/integration_tests/interrupt/git_clone_test.go new file mode 100644 index 0000000000..b30672ce43 --- /dev/null +++ b/tools/integration_tests/interrupt/git_clone_test.go @@ -0,0 +1,54 @@ +// Copyright 2023 Google Inc. All Rights Reserved. +// +// 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. +// +// Provides integration tests for symlink operation on local files. + +package interrupt + +import ( + "testing" + + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/operations" + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/setup" + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/test_setup" +) + +var ( + testDirPath string +) + +type ignoreInterruptsTest struct{} + +func (s *ignoreInterruptsTest) Teardown(t *testing.T) {} + +func (s *ignoreInterruptsTest) Setup(t *testing.T) { + testDirPath = setup.SetupTestDirectory(testDirName) +} + +func (s *ignoreInterruptsTest) TestGitClone(t *testing.T) { + output, err := operations.ExecuteToolCommandf("git", "clone %s %s", "https://github.com/gcsfuse-github-machine-user-bot/test-repository.git", testDirPath) + + if err != nil { + t.Errorf("Git clone failed: %s: %v", string(output), err) + } +} + +//////////////////////////////////////////////////////////////////////// +// Test Function (Runs once before all tests) +//////////////////////////////////////////////////////////////////////// + +func TestIgnoreInterrupts(t *testing.T) { + ts := &ignoreInterruptsTest{} + test_setup.RunTests(t, ts) +} diff --git a/tools/integration_tests/interrupt/interrupt_test.go b/tools/integration_tests/interrupt/interrupt_test.go new file mode 100644 index 0000000000..a4f36cf631 --- /dev/null +++ b/tools/integration_tests/interrupt/interrupt_test.go @@ -0,0 +1,67 @@ +// Copyright 2024 Google Inc. All Rights Reserved. +// +// 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. + +package interrupt + +import ( + "os" + "path" + "testing" + + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/dynamic_mounting" + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/only_dir_mounting" + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/static_mounting" + "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/setup" +) + +const ( + testDirName = "InterruptTest" +) + +//////////////////////////////////////////////////////////////////////// +// Helpers +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// TestMain +//////////////////////////////////////////////////////////////////////// + +func TestMain(m *testing.M) { + setup.ParseSetUpFlags() + setup.ExitWithFailureIfBothTestBucketAndMountedDirectoryFlagsAreNotSet() + + setup.RunTestsForMountedDirectoryFlag(m) + + // Else run tests for testBucket. + // Set up test directory. + setup.SetUpTestDirForTestBucketFlag() + + // Set up flags to run tests on. + // Not setting config file explicitly with 'create-empty-file: false' as it is default. + flags := [][]string{{"--implicit-dirs=true", "--ignore-interrupts"}} + + successCode := static_mounting.RunTests(flags, m) + + if successCode == 0 { + successCode = only_dir_mounting.RunTests(flags, m) + } + + if successCode == 0 { + successCode = dynamic_mounting.RunTests(flags, m) + } + + // Clean up test directory created. + setup.CleanupDirectoryOnGCS(path.Join(setup.TestBucket(), testDirName)) + os.Exit(successCode) +} diff --git a/tools/integration_tests/util/operations/operations.go b/tools/integration_tests/util/operations/operations.go index a1e28a47c7..57f9967970 100644 --- a/tools/integration_tests/util/operations/operations.go +++ b/tools/integration_tests/util/operations/operations.go @@ -35,7 +35,7 @@ func GenerateRandomData(sizeInBytes int64) ([]byte, error) { } // Executes any given tool (e.g. gsutil/gcloud) with given args. -func executeToolCommandf(tool string, format string, args ...any) ([]byte, error) { +func ExecuteToolCommandf(tool string, format string, args ...any) ([]byte, error) { cmdArgs := tool + " " + fmt.Sprintf(format, args...) cmd := exec.Command("/bin/bash", "-c", cmdArgs) @@ -55,5 +55,5 @@ func executeToolCommandf(tool string, format string, args ...any) ([]byte, error // Executes any given gcloud command with given args. func ExecuteGcloudCommandf(format string, args ...any) ([]byte, error) { - return executeToolCommandf("gcloud", format, args...) + return ExecuteToolCommandf("gcloud", format, args...) } From 2210c010e49d87841a87b459e726669e9f4479ad Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Tue, 23 Apr 2024 11:18:58 +0000 Subject: [PATCH 05/16] lint fixes --- internal/fs/fs.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index c7083d233e..bf8b54ce38 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -1421,7 +1421,6 @@ func (fs *fileSystem) SetInodeAttributes( func (fs *fileSystem) ForgetInode( ctx context.Context, op *fuseops.ForgetInodeOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -2193,7 +2192,6 @@ func (fs *fileSystem) ReadFile( func (fs *fileSystem) ReadSymlink( ctx context.Context, op *fuseops.ReadSymlinkOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) // Find the inode. fs.mu.Lock() in := fs.symlinkInodeOrDie(op.Inode) From 55df493e4c12200b2f1f04bc0969afa87d7de98c Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Wed, 24 Apr 2024 10:50:35 +0000 Subject: [PATCH 06/16] use mount config instead of flag --- internal/fs/fs.go | 7 +------ internal/fs/interrupt_test.go | 3 ++- mount.go | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index bf8b54ce38..b4ae402d0c 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -124,9 +124,6 @@ type ServerConfig struct { // File chunk size to read from GCS in one call. Specified in MB. SequentialReadSizeMb int32 - // Allows ignoring interrupts. - IgnoreInterrupts bool - // MountConfig has all the config specified by the user using configFile flag. MountConfig *config.MountConfig } @@ -179,7 +176,6 @@ func NewFileSystem( inodeAttributeCacheTTL: cfg.InodeAttributeCacheTTL, dirTypeCacheTTL: cfg.DirTypeCacheTTL, renameDirLimit: cfg.RenameDirLimit, - ignoreInterrupts: cfg.IgnoreInterrupts, sequentialReadSizeMb: cfg.SequentialReadSizeMb, uid: cfg.Uid, gid: cfg.Gid, @@ -346,7 +342,6 @@ type fileSystem struct { inodeAttributeCacheTTL time.Duration dirTypeCacheTTL time.Duration renameDirLimit int64 - ignoreInterrupts bool sequentialReadSizeMb int32 // The user and group owning everything in the file system. @@ -1315,7 +1310,7 @@ func (fs *fileSystem) StatFS( } func (fs *fileSystem) ignoreInterruptsIfFlagIsSet(ctx context.Context) context.Context { - if fs.ignoreInterrupts { + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { return context.WithoutCancel(ctx) } return ctx diff --git a/internal/fs/interrupt_test.go b/internal/fs/interrupt_test.go index 35bb23b8b3..58c32dca15 100644 --- a/internal/fs/interrupt_test.go +++ b/internal/fs/interrupt_test.go @@ -22,6 +22,7 @@ import ( "context" "testing" + "github.com/googlecloudplatform/gcsfuse/v2/internal/config" "github.com/jacobsa/ogletest" ) @@ -37,7 +38,7 @@ var ignoreInterruptsTest = []struct { func TestIgnoreInterruptsIfFlagIsSet(t *testing.T) { for _, tt := range ignoreInterruptsTest { t.Run(tt.testName, func(t *testing.T) { - fs := &fileSystem{ignoreInterrupts: tt.ignoreInterrupts} + fs := &fileSystem{mountConfig: &config.MountConfig{FileSystemConfig: config.FileSystemConfig{IgnoreInterrupts: tt.ignoreInterrupts}}} ctx, cancel := context.WithCancel(context.Background()) // Call the method and cancel the context diff --git a/mount.go b/mount.go index da32ea06ea..e769de31e8 100644 --- a/mount.go +++ b/mount.go @@ -120,7 +120,6 @@ be interacting with the file system.`) FilePerms: os.FileMode(flags.FileMode), DirPerms: os.FileMode(flags.DirMode), RenameDirLimit: flags.RenameDirLimit, - IgnoreInterrupts: flags.IgnoreInterrupts, SequentialReadSizeMb: flags.SequentialReadSizeMb, EnableNonexistentTypeCache: flags.EnableNonexistentTypeCache, MountConfig: mountConfig, From 513c45dff3074acd5fa600172ebfecce06ca466e Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Wed, 24 Apr 2024 11:06:56 +0000 Subject: [PATCH 07/16] update integration tests to include config file --- tools/integration_tests/interrupt/interrupt_test.go | 12 ++++++++++-- tools/integration_tests/run_e2e_tests.sh | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/integration_tests/interrupt/interrupt_test.go b/tools/integration_tests/interrupt/interrupt_test.go index a4f36cf631..7cac39e8fc 100644 --- a/tools/integration_tests/interrupt/interrupt_test.go +++ b/tools/integration_tests/interrupt/interrupt_test.go @@ -19,6 +19,7 @@ import ( "path" "testing" + "github.com/googlecloudplatform/gcsfuse/v2/internal/config" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/dynamic_mounting" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/only_dir_mounting" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/static_mounting" @@ -48,8 +49,15 @@ func TestMain(m *testing.M) { setup.SetUpTestDirForTestBucketFlag() // Set up flags to run tests on. - // Not setting config file explicitly with 'create-empty-file: false' as it is default. - flags := [][]string{{"--implicit-dirs=true", "--ignore-interrupts"}} + mountConfig := config.MountConfig{ + FileSystemConfig: config.FileSystemConfig{IgnoreInterrupts: true}, + LogConfig: config.LogConfig{ + Severity: config.TRACE, + LogRotateConfig: config.DefaultLogRotateConfig(), + }, + } + flags := [][]string{ + {"--config-file=" + setup.YAMLConfigFile(mountConfig, "config.yaml")}} successCode := static_mounting.RunTests(flags, m) diff --git a/tools/integration_tests/run_e2e_tests.sh b/tools/integration_tests/run_e2e_tests.sh index 0215b6615f..2d7b9396fc 100755 --- a/tools/integration_tests/run_e2e_tests.sh +++ b/tools/integration_tests/run_e2e_tests.sh @@ -46,6 +46,7 @@ TEST_DIR_PARALLEL=( "read_large_files" "explicit_dir" "implicit_dir" + "interrupt" "operations" ) # These tests never become parallel as it is changing bucket permissions. From b38f2aa87ba2414c6174fd63a75ca06c12a2518b Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Wed, 24 Apr 2024 11:11:25 +0000 Subject: [PATCH 08/16] update integration tests to include config file --- tools/integration_tests/interrupt/interrupt_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/integration_tests/interrupt/interrupt_test.go b/tools/integration_tests/interrupt/interrupt_test.go index 7cac39e8fc..da9d75f434 100644 --- a/tools/integration_tests/interrupt/interrupt_test.go +++ b/tools/integration_tests/interrupt/interrupt_test.go @@ -56,7 +56,7 @@ func TestMain(m *testing.M) { LogRotateConfig: config.DefaultLogRotateConfig(), }, } - flags := [][]string{ + flags := [][]string{{"--implicit-dirs=true", "--ignore-interrupts"}, {"--config-file=" + setup.YAMLConfigFile(mountConfig, "config.yaml")}} successCode := static_mounting.RunTests(flags, m) From c2f68e18e38ae1de126117ae49a8f8dc3bbaf4c3 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Fri, 26 Apr 2024 09:48:23 +0000 Subject: [PATCH 09/16] review comments --- internal/fs/fs.go | 130 +++++++++++++++--- internal/fs/interrupt_test.go | 31 ++--- .../interrupt/git_clone_test.go | 98 ++++++++++++- .../util/operations/operations.go | 24 +++- 4 files changed, 236 insertions(+), 47 deletions(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index b4ae402d0c..75fa677bd9 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -1309,18 +1309,24 @@ func (fs *fileSystem) StatFS( return } -func (fs *fileSystem) ignoreInterruptsIfFlagIsSet(ctx context.Context) context.Context { - if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - return context.WithoutCancel(ctx) - } - return ctx +// isolateContextFromParentContext creates a copy of the parent context which is +// not cancelled when parent context is cancelled. +func isolateContextFromParentContext(ctx context.Context) (context.Context, context.CancelFunc) { + ctx = context.WithoutCancel(ctx) + return context.WithCancel(ctx) } // LOCKS_EXCLUDED(fs.mu) func (fs *fileSystem) LookUpInode( ctx context.Context, op *fuseops.LookUpInodeOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the parent directory in question. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1350,7 +1356,13 @@ func (fs *fileSystem) LookUpInode( func (fs *fileSystem) GetInodeAttributes( ctx context.Context, op *fuseops.GetInodeAttributesOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1372,7 +1384,13 @@ func (fs *fileSystem) GetInodeAttributes( func (fs *fileSystem) SetInodeAttributes( ctx context.Context, op *fuseops.SetInodeAttributesOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -1432,7 +1450,13 @@ func (fs *fileSystem) ForgetInode( func (fs *fileSystem) MkDir( ctx context.Context, op *fuseops.MkDirOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1485,7 +1509,13 @@ func (fs *fileSystem) MkDir( func (fs *fileSystem) MkNode( ctx context.Context, op *fuseops.MkNodeOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } if (op.Mode & (iofs.ModeNamedPipe | iofs.ModeSocket)) != 0 { return syscall.ENOTSUP } @@ -1609,7 +1639,13 @@ func (fs *fileSystem) createLocalFile( func (fs *fileSystem) CreateFile( ctx context.Context, op *fuseops.CreateFileOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Create the child. var child inode.Inode if fs.mountConfig.CreateEmptyFile { @@ -1652,7 +1688,13 @@ func (fs *fileSystem) CreateFile( func (fs *fileSystem) CreateSymlink( ctx context.Context, op *fuseops.CreateSymlinkOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1716,7 +1758,13 @@ func (fs *fileSystem) RmDir( ctx context.Context, op *fuseops.RmDirOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -1812,7 +1860,13 @@ func (fs *fileSystem) RmDir( func (fs *fileSystem) Rename( ctx context.Context, op *fuseops.RenameOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the old and new parents. fs.mu.Lock() oldParent := fs.dirInodeOrDie(op.OldParent) @@ -2025,7 +2079,13 @@ func (fs *fileSystem) renameDir( func (fs *fileSystem) Unlink( ctx context.Context, op *fuseops.UnlinkOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the parent. fs.mu.Lock() parent := fs.dirInodeOrDie(op.Parent) @@ -2094,7 +2154,13 @@ func (fs *fileSystem) OpenDir( func (fs *fileSystem) ReadDir( ctx context.Context, op *fuseops.ReadDirOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the handle. fs.mu.Lock() dh := fs.handles[op.Handle].(*handle.DirHandle) @@ -2160,7 +2226,13 @@ func (fs *fileSystem) OpenFile( func (fs *fileSystem) ReadFile( ctx context.Context, op *fuseops.ReadFileOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Save readOp in context for access in logs. ctx = context.WithValue(ctx, gcsx.ReadOp, op) @@ -2205,7 +2277,13 @@ func (fs *fileSystem) ReadSymlink( func (fs *fileSystem) WriteFile( ctx context.Context, op *fuseops.WriteFileOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the inode. fs.mu.Lock() in := fs.fileInodeOrDie(op.Inode) @@ -2226,7 +2304,13 @@ func (fs *fileSystem) WriteFile( func (fs *fileSystem) SyncFile( ctx context.Context, op *fuseops.SyncFileOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the inode. fs.mu.Lock() in := fs.inodeOrDie(op.Inode) @@ -2253,7 +2337,13 @@ func (fs *fileSystem) SyncFile( func (fs *fileSystem) FlushFile( ctx context.Context, op *fuseops.FlushFileOp) (err error) { - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) + if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { + // When ignore interrupts flag is set, we are creating a new context not + // cancellable by parent context. + var cancel context.CancelFunc + ctx, cancel = isolateContextFromParentContext(ctx) + defer cancel() + } // Find the inode. fs.mu.Lock() in := fs.fileInodeOrDie(op.Inode) diff --git a/internal/fs/interrupt_test.go b/internal/fs/interrupt_test.go index 58c32dca15..f6db4361bb 100644 --- a/internal/fs/interrupt_test.go +++ b/internal/fs/interrupt_test.go @@ -22,30 +22,19 @@ import ( "context" "testing" - "github.com/googlecloudplatform/gcsfuse/v2/internal/config" "github.com/jacobsa/ogletest" ) -var ignoreInterruptsTest = []struct { - testName string - ignoreInterrupts bool - err error -}{ - {"Ignore Interrupts", true, nil}, - {"Respect Interrupts", false, context.Canceled}, -} - -func TestIgnoreInterruptsIfFlagIsSet(t *testing.T) { - for _, tt := range ignoreInterruptsTest { - t.Run(tt.testName, func(t *testing.T) { - fs := &fileSystem{mountConfig: &config.MountConfig{FileSystemConfig: config.FileSystemConfig{IgnoreInterrupts: tt.ignoreInterrupts}}} - ctx, cancel := context.WithCancel(context.Background()) +func TestIsolateContextFromParentContext(t *testing.T) { + parentCtx, parentCtxCancel := context.WithCancel(context.Background()) - // Call the method and cancel the context - ctx = fs.ignoreInterruptsIfFlagIsSet(ctx) - cancel() + // Call the method and cancel the parent context + newCtx, newCtxCancel := isolateContextFromParentContext(parentCtx) + parentCtxCancel() - ogletest.AssertEq(tt.err, ctx.Err()) - }) - } + // validate new context is not cancelled after parent's cancellation. + ogletest.AssertEq(nil, newCtx.Err()) + // cancel the new context and validate. + newCtxCancel() + ogletest.AssertEq(context.Canceled, newCtx.Err()) } diff --git a/tools/integration_tests/interrupt/git_clone_test.go b/tools/integration_tests/interrupt/git_clone_test.go index b30672ce43..f7684a08a6 100644 --- a/tools/integration_tests/interrupt/git_clone_test.go +++ b/tools/integration_tests/interrupt/git_clone_test.go @@ -12,22 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// Provides integration tests for symlink operation on local files. +// Provides integration tests for running git operations with ignore interrupts +// flag/config set. package interrupt import ( + "path" "testing" + "github.com/googlecloudplatform/gcsfuse/v2/internal/cache/util" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/operations" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/setup" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/test_setup" ) +const ( + repoURL = "https://github.com/gcsfuse-github-machine-user-bot/test-repository.git" + repoName = "test-repository" + branchName = "test-branch" + testFileName = "testFile" + tool = "git" +) + var ( testDirPath string ) +//////////////////////////////////////////////////////////////////////// +// Boilerplate +//////////////////////////////////////////////////////////////////////// + type ignoreInterruptsTest struct{} func (s *ignoreInterruptsTest) Teardown(t *testing.T) {} @@ -36,11 +51,88 @@ func (s *ignoreInterruptsTest) Setup(t *testing.T) { testDirPath = setup.SetupTestDirectory(testDirName) } +//////////////////////////////////////////////////////////////////////// +// Helpers +//////////////////////////////////////////////////////////////////////// + +func cloneRepository() ([]byte, error) { + return operations.ExecuteToolCommandfInDIrectory(testDirPath, tool, "clone %s", repoURL) +} + +func checkoutBranch(branchName string) ([]byte, error) { + repositoryPath := path.Join(testDirPath, repoName) + return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "checkout %s", branchName) +} + +func emptyCommit() ([]byte, error) { + repositoryPath := path.Join(testDirPath, repoName) + return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "commit --allow-empty -m \" empty commit\"") +} + +func gitAdd(filePath string) ([]byte, error) { + repositoryPath := path.Join(testDirPath, repoName) + return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "add %s", filePath) +} + +func nonEmptyCommit() ([]byte, error) { + repositoryPath := path.Join(testDirPath, repoName) + return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "commit -m \"test\"") +} + +//////////////////////////////////////////////////////////////////////// +// Test scenarios +//////////////////////////////////////////////////////////////////////// + func (s *ignoreInterruptsTest) TestGitClone(t *testing.T) { - output, err := operations.ExecuteToolCommandf("git", "clone %s %s", "https://github.com/gcsfuse-github-machine-user-bot/test-repository.git", testDirPath) + output, err := cloneRepository() + + if err != nil { + t.Errorf("cloneRepository() failed: %s: %v", string(output), err) + } +} + +func (s *ignoreInterruptsTest) TestGitCheckout(t *testing.T) { + _, err := cloneRepository() + if err != nil { + t.Errorf("cloneRepository() failed: %v", err) + } + + output, err := checkoutBranch(branchName) + + if err != nil { + t.Errorf("Git checkout failed: %s: %v", string(output), err) + } +} + +func (s *ignoreInterruptsTest) TestGitEmptyCommit(t *testing.T) { + _, err := cloneRepository() + if err != nil { + t.Errorf("cloneRepository() failed: %v", err) + } + + output, err := emptyCommit() + + if err != nil { + t.Errorf("Git empty commit failed: %s: %v", string(output), err) + } +} + +func (s *ignoreInterruptsTest) TestGitCommitWithChanges(t *testing.T) { + _, err := cloneRepository() + if err != nil { + t.Errorf("cloneRepository() failed: %v", err) + } + + filePath := path.Join(testDirPath, repoName, testFileName) + operations.CreateFileOfSize(util.MiB, filePath, t) + output, err := gitAdd(filePath) + if err != nil { + t.Errorf("Git add failed: %s: %v", string(output), err) + } + output, err = nonEmptyCommit() if err != nil { - t.Errorf("Git clone failed: %s: %v", string(output), err) + t.Errorf("Git empty commit failed: %s: %v", string(output), err) } } diff --git a/tools/integration_tests/util/operations/operations.go b/tools/integration_tests/util/operations/operations.go index 57f9967970..8b6e05bb8c 100644 --- a/tools/integration_tests/util/operations/operations.go +++ b/tools/integration_tests/util/operations/operations.go @@ -35,10 +35,23 @@ func GenerateRandomData(sizeInBytes int64) ([]byte, error) { } // Executes any given tool (e.g. gsutil/gcloud) with given args. -func ExecuteToolCommandf(tool string, format string, args ...any) ([]byte, error) { +func executeToolCommandf(tool string, format string, args ...any) ([]byte, error) { cmdArgs := tool + " " + fmt.Sprintf(format, args...) cmd := exec.Command("/bin/bash", "-c", cmdArgs) + return runCommand(cmd) +} + +// Executes any given tool (e.g. gsutil/gcloud) with given args in specified directory. +func ExecuteToolCommandfInDIrectory(dirPath, tool, format string, args ...any) ([]byte, error) { + cmdArgs := tool + " " + fmt.Sprintf(format, args...) + cmd := exec.Command("/bin/bash", "-c", cmdArgs) + cmd.Dir = dirPath + + return runCommand(cmd) +} + +func runCommand(cmd *exec.Cmd) ([]byte, error) { var stdout bytes.Buffer var stderr bytes.Buffer @@ -47,13 +60,18 @@ func ExecuteToolCommandf(tool string, format string, args ...any) ([]byte, error err := cmd.Run() if err != nil { - return stdout.Bytes(), fmt.Errorf("failed command '%s': %v, %s", cmdArgs, err, stderr.String()) + return stdout.Bytes(), fmt.Errorf("failed command '%s': %v, %s", cmd.String(), err, stderr.String()) } return stdout.Bytes(), nil } +// Executes any given gsutil command with given args. +func ExecuteGsutilCommandf(format string, args ...any) ([]byte, error) { + return executeToolCommandf("gsutil", format, args...) +} + // Executes any given gcloud command with given args. func ExecuteGcloudCommandf(format string, args ...any) ([]byte, error) { - return ExecuteToolCommandf("gcloud", format, args...) + return executeToolCommandf("gcloud", format, args...) } From 42deae3b92e03d2b5f7de52b611824960ad32dc8 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Fri, 26 Apr 2024 09:48:38 +0000 Subject: [PATCH 10/16] run tests only for static mounting --- tools/integration_tests/interrupt/interrupt_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/integration_tests/interrupt/interrupt_test.go b/tools/integration_tests/interrupt/interrupt_test.go index da9d75f434..3c3e55a90b 100644 --- a/tools/integration_tests/interrupt/interrupt_test.go +++ b/tools/integration_tests/interrupt/interrupt_test.go @@ -20,8 +20,6 @@ import ( "testing" "github.com/googlecloudplatform/gcsfuse/v2/internal/config" - "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/dynamic_mounting" - "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/only_dir_mounting" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/mounting/static_mounting" "github.com/googlecloudplatform/gcsfuse/v2/tools/integration_tests/util/setup" ) @@ -61,14 +59,6 @@ func TestMain(m *testing.M) { successCode := static_mounting.RunTests(flags, m) - if successCode == 0 { - successCode = only_dir_mounting.RunTests(flags, m) - } - - if successCode == 0 { - successCode = dynamic_mounting.RunTests(flags, m) - } - // Clean up test directory created. setup.CleanupDirectoryOnGCS(path.Join(setup.TestBucket(), testDirName)) os.Exit(successCode) From fa15bc208069a088f43ec6f6ad64619f27307577 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Fri, 26 Apr 2024 09:52:11 +0000 Subject: [PATCH 11/16] minor update to comments --- internal/fs/fs.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 75fa677bd9..52b245f4e7 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -1321,7 +1321,7 @@ func (fs *fileSystem) LookUpInode( ctx context.Context, op *fuseops.LookUpInodeOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1357,7 +1357,7 @@ func (fs *fileSystem) GetInodeAttributes( ctx context.Context, op *fuseops.GetInodeAttributesOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1385,7 +1385,7 @@ func (fs *fileSystem) SetInodeAttributes( ctx context.Context, op *fuseops.SetInodeAttributesOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1451,7 +1451,7 @@ func (fs *fileSystem) MkDir( ctx context.Context, op *fuseops.MkDirOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1510,7 +1510,7 @@ func (fs *fileSystem) MkNode( ctx context.Context, op *fuseops.MkNodeOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1640,7 +1640,7 @@ func (fs *fileSystem) CreateFile( ctx context.Context, op *fuseops.CreateFileOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1689,7 +1689,7 @@ func (fs *fileSystem) CreateSymlink( ctx context.Context, op *fuseops.CreateSymlinkOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1759,7 +1759,7 @@ func (fs *fileSystem) RmDir( ctx context.Context, op *fuseops.RmDirOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -1861,7 +1861,7 @@ func (fs *fileSystem) Rename( ctx context.Context, op *fuseops.RenameOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -2080,7 +2080,7 @@ func (fs *fileSystem) Unlink( ctx context.Context, op *fuseops.UnlinkOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -2155,7 +2155,7 @@ func (fs *fileSystem) ReadDir( ctx context.Context, op *fuseops.ReadDirOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -2227,7 +2227,7 @@ func (fs *fileSystem) ReadFile( ctx context.Context, op *fuseops.ReadFileOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -2278,7 +2278,7 @@ func (fs *fileSystem) WriteFile( ctx context.Context, op *fuseops.WriteFileOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -2305,7 +2305,7 @@ func (fs *fileSystem) SyncFile( ctx context.Context, op *fuseops.SyncFileOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) @@ -2338,7 +2338,7 @@ func (fs *fileSystem) FlushFile( ctx context.Context, op *fuseops.FlushFileOp) (err error) { if fs.mountConfig.FileSystemConfig.IgnoreInterrupts { - // When ignore interrupts flag is set, we are creating a new context not + // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc ctx, cancel = isolateContextFromParentContext(ctx) From 329986b082c0013b4a55730c7bfe9c5cf61b1573 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Mon, 29 Apr 2024 04:47:42 +0000 Subject: [PATCH 12/16] minor log fix --- tools/integration_tests/interrupt/git_clone_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/integration_tests/interrupt/git_clone_test.go b/tools/integration_tests/interrupt/git_clone_test.go index f7684a08a6..46eb8091ea 100644 --- a/tools/integration_tests/interrupt/git_clone_test.go +++ b/tools/integration_tests/interrupt/git_clone_test.go @@ -87,7 +87,7 @@ func (s *ignoreInterruptsTest) TestGitClone(t *testing.T) { output, err := cloneRepository() if err != nil { - t.Errorf("cloneRepository() failed: %s: %v", string(output), err) + t.Errorf("Git clone failed: %s: %v", string(output), err) } } @@ -132,7 +132,7 @@ func (s *ignoreInterruptsTest) TestGitCommitWithChanges(t *testing.T) { output, err = nonEmptyCommit() if err != nil { - t.Errorf("Git empty commit failed: %s: %v", string(output), err) + t.Errorf("Git commit failed: %s: %v", string(output), err) } } From ea14d424fb416ff546842a6019d29bb0604754f7 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Thu, 2 May 2024 05:00:53 +0000 Subject: [PATCH 13/16] rebase changes --- tools/integration_tests/util/operations/operations.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/integration_tests/util/operations/operations.go b/tools/integration_tests/util/operations/operations.go index 8b6e05bb8c..7635a55f05 100644 --- a/tools/integration_tests/util/operations/operations.go +++ b/tools/integration_tests/util/operations/operations.go @@ -66,11 +66,6 @@ func runCommand(cmd *exec.Cmd) ([]byte, error) { return stdout.Bytes(), nil } -// Executes any given gsutil command with given args. -func ExecuteGsutilCommandf(format string, args ...any) ([]byte, error) { - return executeToolCommandf("gsutil", format, args...) -} - // Executes any given gcloud command with given args. func ExecuteGcloudCommandf(format string, args ...any) ([]byte, error) { return executeToolCommandf("gcloud", format, args...) From e1f1409f6eac9d34c0aa308974006be96488c1d1 Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Thu, 2 May 2024 08:45:08 +0000 Subject: [PATCH 14/16] typo in function name --- tools/integration_tests/interrupt/git_clone_test.go | 10 +++++----- tools/integration_tests/util/operations/operations.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/integration_tests/interrupt/git_clone_test.go b/tools/integration_tests/interrupt/git_clone_test.go index 46eb8091ea..9bd451ebfe 100644 --- a/tools/integration_tests/interrupt/git_clone_test.go +++ b/tools/integration_tests/interrupt/git_clone_test.go @@ -56,27 +56,27 @@ func (s *ignoreInterruptsTest) Setup(t *testing.T) { //////////////////////////////////////////////////////////////////////// func cloneRepository() ([]byte, error) { - return operations.ExecuteToolCommandfInDIrectory(testDirPath, tool, "clone %s", repoURL) + return operations.ExecuteToolCommandfInDirectory(testDirPath, tool, "clone %s", repoURL) } func checkoutBranch(branchName string) ([]byte, error) { repositoryPath := path.Join(testDirPath, repoName) - return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "checkout %s", branchName) + return operations.ExecuteToolCommandfInDirectory(repositoryPath, tool, "checkout %s", branchName) } func emptyCommit() ([]byte, error) { repositoryPath := path.Join(testDirPath, repoName) - return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "commit --allow-empty -m \" empty commit\"") + return operations.ExecuteToolCommandfInDirectory(repositoryPath, tool, "commit --allow-empty -m \" empty commit\"") } func gitAdd(filePath string) ([]byte, error) { repositoryPath := path.Join(testDirPath, repoName) - return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "add %s", filePath) + return operations.ExecuteToolCommandfInDirectory(repositoryPath, tool, "add %s", filePath) } func nonEmptyCommit() ([]byte, error) { repositoryPath := path.Join(testDirPath, repoName) - return operations.ExecuteToolCommandfInDIrectory(repositoryPath, tool, "commit -m \"test\"") + return operations.ExecuteToolCommandfInDirectory(repositoryPath, tool, "commit -m \"test\"") } //////////////////////////////////////////////////////////////////////// diff --git a/tools/integration_tests/util/operations/operations.go b/tools/integration_tests/util/operations/operations.go index 7635a55f05..c1fbb6da2e 100644 --- a/tools/integration_tests/util/operations/operations.go +++ b/tools/integration_tests/util/operations/operations.go @@ -43,7 +43,7 @@ func executeToolCommandf(tool string, format string, args ...any) ([]byte, error } // Executes any given tool (e.g. gsutil/gcloud) with given args in specified directory. -func ExecuteToolCommandfInDIrectory(dirPath, tool, format string, args ...any) ([]byte, error) { +func ExecuteToolCommandfInDirectory(dirPath, tool, format string, args ...any) ([]byte, error) { cmdArgs := tool + " " + fmt.Sprintf(format, args...) cmd := exec.Command("/bin/bash", "-c", cmdArgs) cmd.Dir = dirPath From 0b8d7f164d5f715f7ff9b1151816c4762340784d Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Thu, 2 May 2024 11:22:59 +0000 Subject: [PATCH 15/16] review comments --- go.mod | 3 + go.sum | 3 +- internal/fs/fs.go | 38 +++--- internal/fs/interrupt_test.go | 40 ------ internal/util/util.go | 8 ++ internal/util/util_test.go | 117 ++++++++++-------- .../interrupt/interrupt_test.go | 4 - 7 files changed, 96 insertions(+), 117 deletions(-) delete mode 100644 internal/fs/interrupt_test.go diff --git a/go.mod b/go.mod index a0a9378654..e869e91843 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/jacobsa/syncutil v0.0.0-20180201203307-228ac8e5a6c3 github.com/jacobsa/timeutil v0.0.0-20170205232429-577e5acbbcf6 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 + github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.14 go.opencensus.io v0.24.0 golang.org/x/net v0.22.0 @@ -46,6 +47,7 @@ require ( github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/envoyproxy/go-control-plane v0.12.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -61,6 +63,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/pkg/xattr v0.4.9 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/prometheus v0.35.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index 332e9ed9a4..f72878f69e 100644 --- a/go.sum +++ b/go.sum @@ -1076,8 +1076,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 52b245f4e7..0e09edc47d 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -40,6 +40,7 @@ import ( "github.com/googlecloudplatform/gcsfuse/v2/internal/locker" "github.com/googlecloudplatform/gcsfuse/v2/internal/logger" "github.com/googlecloudplatform/gcsfuse/v2/internal/storage/gcs" + . "github.com/googlecloudplatform/gcsfuse/v2/internal/util" "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" @@ -1309,13 +1310,6 @@ func (fs *fileSystem) StatFS( return } -// isolateContextFromParentContext creates a copy of the parent context which is -// not cancelled when parent context is cancelled. -func isolateContextFromParentContext(ctx context.Context) (context.Context, context.CancelFunc) { - ctx = context.WithoutCancel(ctx) - return context.WithCancel(ctx) -} - // LOCKS_EXCLUDED(fs.mu) func (fs *fileSystem) LookUpInode( ctx context.Context, @@ -1324,7 +1318,7 @@ func (fs *fileSystem) LookUpInode( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent directory in question. @@ -1360,7 +1354,7 @@ func (fs *fileSystem) GetInodeAttributes( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -1388,7 +1382,7 @@ func (fs *fileSystem) SetInodeAttributes( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -1454,7 +1448,7 @@ func (fs *fileSystem) MkDir( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -1513,7 +1507,7 @@ func (fs *fileSystem) MkNode( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } if (op.Mode & (iofs.ModeNamedPipe | iofs.ModeSocket)) != 0 { @@ -1643,7 +1637,7 @@ func (fs *fileSystem) CreateFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Create the child. @@ -1692,7 +1686,7 @@ func (fs *fileSystem) CreateSymlink( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -1762,7 +1756,7 @@ func (fs *fileSystem) RmDir( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -1864,7 +1858,7 @@ func (fs *fileSystem) Rename( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the old and new parents. @@ -2083,7 +2077,7 @@ func (fs *fileSystem) Unlink( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -2158,7 +2152,7 @@ func (fs *fileSystem) ReadDir( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the handle. @@ -2230,7 +2224,7 @@ func (fs *fileSystem) ReadFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Save readOp in context for access in logs. @@ -2281,7 +2275,7 @@ func (fs *fileSystem) WriteFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -2308,7 +2302,7 @@ func (fs *fileSystem) SyncFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -2341,7 +2335,7 @@ func (fs *fileSystem) FlushFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = isolateContextFromParentContext(ctx) + ctx, cancel = IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. diff --git a/internal/fs/interrupt_test.go b/internal/fs/interrupt_test.go deleted file mode 100644 index f6db4361bb..0000000000 --- a/internal/fs/interrupt_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 Google Inc. All Rights Reserved. -// -// 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. - -// A collection of tests for a file system where we do not attempt to write to -// the file system at all. Rather we set up contents in a GCS bucket out of -// band, wait for them to be available, and then read them via the file system. - -package fs - -import ( - "context" - "testing" - - "github.com/jacobsa/ogletest" -) - -func TestIsolateContextFromParentContext(t *testing.T) { - parentCtx, parentCtxCancel := context.WithCancel(context.Background()) - - // Call the method and cancel the parent context - newCtx, newCtxCancel := isolateContextFromParentContext(parentCtx) - parentCtxCancel() - - // validate new context is not cancelled after parent's cancellation. - ogletest.AssertEq(nil, newCtx.Err()) - // cancel the new context and validate. - newCtxCancel() - ogletest.AssertEq(context.Canceled, newCtx.Err()) -} diff --git a/internal/util/util.go b/internal/util/util.go index 88ec6d97fd..1343591bd9 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -15,6 +15,7 @@ package util import ( + "context" "encoding/json" "fmt" "math" @@ -102,3 +103,10 @@ func BytesToHigherMiBs(bytes uint64) uint64 { const bytesInOneMiB uint64 = 1 << 20 return uint64(math.Ceil(float64(bytes) / float64(bytesInOneMiB))) } + +// IsolateContextFromParentContext creates a copy of the parent context which is +// not cancelled when parent context is cancelled. +func IsolateContextFromParentContext(ctx context.Context) (context.Context, context.CancelFunc) { + ctx = context.WithoutCancel(ctx) + return context.WithCancel(ctx) +} diff --git a/internal/util/util_test.go b/internal/util/util_test.go index b9dbd9f9a0..eaa75cce98 100644 --- a/internal/util/util_test.go +++ b/internal/util/util_test.go @@ -15,137 +15,140 @@ package util import ( + "context" "errors" "math" "os" "path/filepath" "testing" - . "github.com/jacobsa/ogletest" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" ) const gcsFuseParentProcessDir = "/var/generic/google" -func TestUtil(t *testing.T) { RunTests(t) } - //////////////////////////////////////////////////////////////////////// // Boilerplate //////////////////////////////////////////////////////////////////////// type UtilTest struct { + suite.Suite } -func init() { RegisterTestSuite(&UtilTest{}) } +func TestUtilSuite(t *testing.T) { + suite.Run(t, new(UtilTest)) +} //////////////////////////////////////////////////////////////////////// // Tests //////////////////////////////////////////////////////////////////////// -func (t *UtilTest) ResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithTilda() { +func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithTilda() { resolvedPath, err := GetResolvedPath("~/test.txt") - AssertEq(nil, err) + assert.Equal(suite.T(), nil, err) homeDir, err := os.UserHomeDir() - AssertEq(nil, err) - ExpectEq(filepath.Join(homeDir, "test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(homeDir, "test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDot() { +func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDot() { resolvedPath, err := GetResolvedPath("./test.txt") - AssertEq(nil, err) + assert.Equal(suite.T(), nil, err) currentWorkingDir, err := os.Getwd() - AssertEq(nil, err) - ExpectEq(filepath.Join(currentWorkingDir, "./test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(currentWorkingDir, "./test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDoubleDot() { +func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDoubleDot() { resolvedPath, err := GetResolvedPath("../test.txt") - AssertEq(nil, err) + assert.Equal(suite.T(), nil, err) currentWorkingDir, err := os.Getwd() - AssertEq(nil, err) - ExpectEq(filepath.Join(currentWorkingDir, "../test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(currentWorkingDir, "../test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvNotSetAndRelativePath() { +func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndRelativePath() { resolvedPath, err := GetResolvedPath("test.txt") - AssertEq(nil, err) + assert.Equal(suite.T(), nil, err) currentWorkingDir, err := os.Getwd() - AssertEq(nil, err) - ExpectEq(filepath.Join(currentWorkingDir, "test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(currentWorkingDir, "test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvNotSetAndAbsoluteFilePath() { +func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndAbsoluteFilePath() { resolvedPath, err := GetResolvedPath("/var/dir/test.txt") - AssertEq(nil, err) - ExpectEq("/var/dir/test.txt", resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), "/var/dir/test.txt", resolvedPath) } -func (t *UtilTest) ResolveEmptyFilePath() { +func (suite *UtilTest) ResolveEmptyFilePath() { resolvedPath, err := GetResolvedPath("") - AssertEq(nil, err) - ExpectEq("", resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), "", resolvedPath) } // Below all tests when GCSFUSE_PARENT_PROCESS_DIR env variable is set. // By setting this environment variable, resolve will work for child process. -func (t *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithTilda() { +func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithTilda() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("~/test.txt") - AssertEq(nil, err) + assert.Equal(suite.T(), nil, err) homeDir, err := os.UserHomeDir() - AssertEq(nil, err) - ExpectEq(filepath.Join(homeDir, "test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(homeDir, "test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDot() { +func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDot() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("./test.txt") - AssertEq(nil, err) - ExpectEq(filepath.Join(gcsFuseParentProcessDir, "./test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(gcsFuseParentProcessDir, "./test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDoubleDot() { +func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDoubleDot() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("../test.txt") - AssertEq(nil, err) - ExpectEq(filepath.Join(gcsFuseParentProcessDir, "../test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(gcsFuseParentProcessDir, "../test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvSetAndRelativePath() { +func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndRelativePath() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("test.txt") - AssertEq(nil, err) - ExpectEq(filepath.Join(gcsFuseParentProcessDir, "test.txt"), resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), filepath.Join(gcsFuseParentProcessDir, "test.txt"), resolvedPath) } -func (t *UtilTest) ResolveWhenParentProcDirEnvSetAndAbsoluteFilePath() { +func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndAbsoluteFilePath() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("/var/dir/test.txt") - AssertEq(nil, err) - ExpectEq("/var/dir/test.txt", resolvedPath) + assert.Equal(suite.T(), nil, err) + assert.Equal(suite.T(), "/var/dir/test.txt", resolvedPath) } -func (t *UtilTest) TestStringifyShouldReturnAllFieldsPassedInCustomObjectAsMarshalledString() { +func (suite *UtilTest) TestStringifyShouldReturnAllFieldsPassedInCustomObjectAsMarshalledString() { sampleMap := map[string]int{ "1": 1, "2": 2, @@ -163,10 +166,10 @@ func (t *UtilTest) TestStringifyShouldReturnAllFieldsPassedInCustomObjectAsMarsh actual, _ := Stringify(customObject) expected := "{\"Value\":\"test_value\",\"NestedValue\":{\"SomeField\":10,\"SomeOther\":{\"1\":1,\"2\":2,\"3\":3}}}" - AssertEq(expected, actual) + assert.Equal(suite.T(), expected, actual) } -func (t *UtilTest) TestStringifyShouldReturnEmptyStringWhenMarshalErrorsOut() { +func (suite *UtilTest) TestStringifyShouldReturnEmptyStringWhenMarshalErrorsOut() { customInstance := customTypeForError{ value: "example", } @@ -174,7 +177,7 @@ func (t *UtilTest) TestStringifyShouldReturnEmptyStringWhenMarshalErrorsOut() { actual, _ := Stringify(customInstance) expected := "" - AssertEq(expected, actual) + assert.Equal(suite.T(), expected, actual) } type customTypeForSuccess struct { @@ -194,7 +197,7 @@ func (c customTypeForError) MarshalJSON() ([]byte, error) { return nil, errors.New("intentional error during JSON marshaling") } -func (t *UtilTest) TestMiBsToBytes() { +func (suite *UtilTest) TestMiBsToBytes() { cases := []struct { mib uint64 bytes uint64 @@ -222,11 +225,11 @@ func (t *UtilTest) TestMiBsToBytes() { } for _, tc := range cases { - AssertEq(tc.bytes, MiBsToBytes(tc.mib)) + assert.Equal(suite.T(), tc.bytes, MiBsToBytes(tc.mib)) } } -func (t *UtilTest) TestBytesToHigherMiBs() { +func (suite *UtilTest) TestBytesToHigherMiBs() { cases := []struct { bytes uint64 mib uint64 @@ -258,6 +261,20 @@ func (t *UtilTest) TestBytesToHigherMiBs() { } for _, tc := range cases { - AssertEq(tc.mib, BytesToHigherMiBs(tc.bytes)) + assert.Equal(suite.T(), tc.mib, BytesToHigherMiBs(tc.bytes)) } } + +func (suite *UtilTest) TestIsolateContextFromParentContext() { + parentCtx, parentCtxCancel := context.WithCancel(context.Background()) + + // Call the method and cancel the parent context. + newCtx, newCtxCancel := IsolateContextFromParentContext(parentCtx) + parentCtxCancel() + + // Validate new context is not cancelled after parent's cancellation. + assert.NoError(suite.T(), newCtx.Err()) + // Cancel the new context and validate. + newCtxCancel() + assert.ErrorIs(suite.T(), newCtx.Err(), context.Canceled) +} diff --git a/tools/integration_tests/interrupt/interrupt_test.go b/tools/integration_tests/interrupt/interrupt_test.go index 3c3e55a90b..5700f06c2b 100644 --- a/tools/integration_tests/interrupt/interrupt_test.go +++ b/tools/integration_tests/interrupt/interrupt_test.go @@ -28,10 +28,6 @@ const ( testDirName = "InterruptTest" ) -//////////////////////////////////////////////////////////////////////// -// Helpers -//////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// // TestMain //////////////////////////////////////////////////////////////////////// From 3bdb9eed1d448bf4b9aaf64ee1db00b6c3e1aa3c Mon Sep 17 00:00:00 2001 From: Ashmeen Kaur Date: Thu, 2 May 2024 11:45:44 +0000 Subject: [PATCH 16/16] review comments --- internal/fs/fs.go | 44 ++++++++--------- internal/util/util_test.go | 98 +++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index 0e09edc47d..0724748392 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -31,7 +31,7 @@ import ( "github.com/googlecloudplatform/gcsfuse/v2/internal/cache/file" "github.com/googlecloudplatform/gcsfuse/v2/internal/cache/file/downloader" "github.com/googlecloudplatform/gcsfuse/v2/internal/cache/lru" - "github.com/googlecloudplatform/gcsfuse/v2/internal/cache/util" + cacheutil "github.com/googlecloudplatform/gcsfuse/v2/internal/cache/util" "github.com/googlecloudplatform/gcsfuse/v2/internal/config" "github.com/googlecloudplatform/gcsfuse/v2/internal/contentcache" "github.com/googlecloudplatform/gcsfuse/v2/internal/fs/handle" @@ -40,7 +40,7 @@ import ( "github.com/googlecloudplatform/gcsfuse/v2/internal/locker" "github.com/googlecloudplatform/gcsfuse/v2/internal/logger" "github.com/googlecloudplatform/gcsfuse/v2/internal/storage/gcs" - . "github.com/googlecloudplatform/gcsfuse/v2/internal/util" + "github.com/googlecloudplatform/gcsfuse/v2/internal/util" "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" @@ -224,7 +224,7 @@ func createFileCacheHandler(cfg *ServerConfig) (fileCacheHandler *file.CacheHand if cfg.MountConfig.FileCacheConfig.MaxSizeMB == -1 { sizeInBytes = math.MaxUint64 } else { - sizeInBytes = uint64(cfg.MountConfig.FileCacheConfig.MaxSizeMB) * util.MiB + sizeInBytes = uint64(cfg.MountConfig.FileCacheConfig.MaxSizeMB) * cacheutil.MiB } fileInfoCache := lru.NewCache(sizeInBytes) @@ -232,12 +232,12 @@ func createFileCacheHandler(cfg *ServerConfig) (fileCacheHandler *file.CacheHand // Adding a new directory inside cacheDir to keep file-cache separate from // metadata cache if and when we support storing metadata cache on disk in // the future. - cacheDir = path.Join(cacheDir, util.FileCache) + cacheDir = path.Join(cacheDir, cacheutil.FileCache) - filePerm := util.DefaultFilePerm - dirPerm := util.DefaultDirPerm + filePerm := cacheutil.DefaultFilePerm + dirPerm := cacheutil.DefaultDirPerm - cacheDirErr := util.CreateCacheDirectoryIfNotPresentAt(cacheDir, dirPerm) + cacheDirErr := cacheutil.CreateCacheDirectoryIfNotPresentAt(cacheDir, dirPerm) if cacheDirErr != nil { return nil, fmt.Errorf("createFileCacheHandler: while creating file cache directory: %w", cacheDirErr) } @@ -1318,7 +1318,7 @@ func (fs *fileSystem) LookUpInode( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent directory in question. @@ -1354,7 +1354,7 @@ func (fs *fileSystem) GetInodeAttributes( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -1382,7 +1382,7 @@ func (fs *fileSystem) SetInodeAttributes( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -1448,7 +1448,7 @@ func (fs *fileSystem) MkDir( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -1507,7 +1507,7 @@ func (fs *fileSystem) MkNode( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } if (op.Mode & (iofs.ModeNamedPipe | iofs.ModeSocket)) != 0 { @@ -1637,7 +1637,7 @@ func (fs *fileSystem) CreateFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Create the child. @@ -1686,7 +1686,7 @@ func (fs *fileSystem) CreateSymlink( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -1756,7 +1756,7 @@ func (fs *fileSystem) RmDir( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -1858,7 +1858,7 @@ func (fs *fileSystem) Rename( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the old and new parents. @@ -2077,7 +2077,7 @@ func (fs *fileSystem) Unlink( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the parent. @@ -2152,7 +2152,7 @@ func (fs *fileSystem) ReadDir( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the handle. @@ -2224,7 +2224,7 @@ func (fs *fileSystem) ReadFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Save readOp in context for access in logs. @@ -2275,7 +2275,7 @@ func (fs *fileSystem) WriteFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -2302,7 +2302,7 @@ func (fs *fileSystem) SyncFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. @@ -2335,7 +2335,7 @@ func (fs *fileSystem) FlushFile( // When ignore interrupts config is set, we are creating a new context not // cancellable by parent context. var cancel context.CancelFunc - ctx, cancel = IsolateContextFromParentContext(ctx) + ctx, cancel = util.IsolateContextFromParentContext(ctx) defer cancel() } // Find the inode. diff --git a/internal/util/util_test.go b/internal/util/util_test.go index eaa75cce98..38bbd91eaf 100644 --- a/internal/util/util_test.go +++ b/internal/util/util_test.go @@ -44,111 +44,111 @@ func TestUtilSuite(t *testing.T) { // Tests //////////////////////////////////////////////////////////////////////// -func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithTilda() { +func (ts *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithTilda() { resolvedPath, err := GetResolvedPath("~/test.txt") - assert.Equal(suite.T(), nil, err) + assert.Equal(ts.T(), nil, err) homeDir, err := os.UserHomeDir() - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(homeDir, "test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(homeDir, "test.txt"), resolvedPath) } -func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDot() { +func (ts *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDot() { resolvedPath, err := GetResolvedPath("./test.txt") - assert.Equal(suite.T(), nil, err) + assert.Equal(ts.T(), nil, err) currentWorkingDir, err := os.Getwd() - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(currentWorkingDir, "./test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(currentWorkingDir, "./test.txt"), resolvedPath) } -func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDoubleDot() { +func (ts *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndFilePathStartsWithDoubleDot() { resolvedPath, err := GetResolvedPath("../test.txt") - assert.Equal(suite.T(), nil, err) + assert.Equal(ts.T(), nil, err) currentWorkingDir, err := os.Getwd() - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(currentWorkingDir, "../test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(currentWorkingDir, "../test.txt"), resolvedPath) } -func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndRelativePath() { +func (ts *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndRelativePath() { resolvedPath, err := GetResolvedPath("test.txt") - assert.Equal(suite.T(), nil, err) + assert.Equal(ts.T(), nil, err) currentWorkingDir, err := os.Getwd() - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(currentWorkingDir, "test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(currentWorkingDir, "test.txt"), resolvedPath) } -func (suite *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndAbsoluteFilePath() { +func (ts *UtilTest) TestResolveWhenParentProcDirEnvNotSetAndAbsoluteFilePath() { resolvedPath, err := GetResolvedPath("/var/dir/test.txt") - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), "/var/dir/test.txt", resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), "/var/dir/test.txt", resolvedPath) } -func (suite *UtilTest) ResolveEmptyFilePath() { +func (ts *UtilTest) ResolveEmptyFilePath() { resolvedPath, err := GetResolvedPath("") - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), "", resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), "", resolvedPath) } // Below all tests when GCSFUSE_PARENT_PROCESS_DIR env variable is set. // By setting this environment variable, resolve will work for child process. -func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithTilda() { +func (ts *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithTilda() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("~/test.txt") - assert.Equal(suite.T(), nil, err) + assert.Equal(ts.T(), nil, err) homeDir, err := os.UserHomeDir() - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(homeDir, "test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(homeDir, "test.txt"), resolvedPath) } -func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDot() { +func (ts *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDot() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("./test.txt") - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(gcsFuseParentProcessDir, "./test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(gcsFuseParentProcessDir, "./test.txt"), resolvedPath) } -func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDoubleDot() { +func (ts *UtilTest) ResolveWhenParentProcDirEnvSetAndFilePathStartsWithDoubleDot() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("../test.txt") - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(gcsFuseParentProcessDir, "../test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(gcsFuseParentProcessDir, "../test.txt"), resolvedPath) } -func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndRelativePath() { +func (ts *UtilTest) ResolveWhenParentProcDirEnvSetAndRelativePath() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("test.txt") - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), filepath.Join(gcsFuseParentProcessDir, "test.txt"), resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), filepath.Join(gcsFuseParentProcessDir, "test.txt"), resolvedPath) } -func (suite *UtilTest) ResolveWhenParentProcDirEnvSetAndAbsoluteFilePath() { +func (ts *UtilTest) ResolveWhenParentProcDirEnvSetAndAbsoluteFilePath() { os.Setenv(GCSFUSE_PARENT_PROCESS_DIR, gcsFuseParentProcessDir) defer os.Unsetenv(GCSFUSE_PARENT_PROCESS_DIR) resolvedPath, err := GetResolvedPath("/var/dir/test.txt") - assert.Equal(suite.T(), nil, err) - assert.Equal(suite.T(), "/var/dir/test.txt", resolvedPath) + assert.Equal(ts.T(), nil, err) + assert.Equal(ts.T(), "/var/dir/test.txt", resolvedPath) } -func (suite *UtilTest) TestStringifyShouldReturnAllFieldsPassedInCustomObjectAsMarshalledString() { +func (ts *UtilTest) TestStringifyShouldReturnAllFieldsPassedInCustomObjectAsMarshalledString() { sampleMap := map[string]int{ "1": 1, "2": 2, @@ -166,10 +166,10 @@ func (suite *UtilTest) TestStringifyShouldReturnAllFieldsPassedInCustomObjectAsM actual, _ := Stringify(customObject) expected := "{\"Value\":\"test_value\",\"NestedValue\":{\"SomeField\":10,\"SomeOther\":{\"1\":1,\"2\":2,\"3\":3}}}" - assert.Equal(suite.T(), expected, actual) + assert.Equal(ts.T(), expected, actual) } -func (suite *UtilTest) TestStringifyShouldReturnEmptyStringWhenMarshalErrorsOut() { +func (ts *UtilTest) TestStringifyShouldReturnEmptyStringWhenMarshalErrorsOut() { customInstance := customTypeForError{ value: "example", } @@ -177,7 +177,7 @@ func (suite *UtilTest) TestStringifyShouldReturnEmptyStringWhenMarshalErrorsOut( actual, _ := Stringify(customInstance) expected := "" - assert.Equal(suite.T(), expected, actual) + assert.Equal(ts.T(), expected, actual) } type customTypeForSuccess struct { @@ -197,7 +197,7 @@ func (c customTypeForError) MarshalJSON() ([]byte, error) { return nil, errors.New("intentional error during JSON marshaling") } -func (suite *UtilTest) TestMiBsToBytes() { +func (ts *UtilTest) TestMiBsToBytes() { cases := []struct { mib uint64 bytes uint64 @@ -225,11 +225,11 @@ func (suite *UtilTest) TestMiBsToBytes() { } for _, tc := range cases { - assert.Equal(suite.T(), tc.bytes, MiBsToBytes(tc.mib)) + assert.Equal(ts.T(), tc.bytes, MiBsToBytes(tc.mib)) } } -func (suite *UtilTest) TestBytesToHigherMiBs() { +func (ts *UtilTest) TestBytesToHigherMiBs() { cases := []struct { bytes uint64 mib uint64 @@ -261,11 +261,11 @@ func (suite *UtilTest) TestBytesToHigherMiBs() { } for _, tc := range cases { - assert.Equal(suite.T(), tc.mib, BytesToHigherMiBs(tc.bytes)) + assert.Equal(ts.T(), tc.mib, BytesToHigherMiBs(tc.bytes)) } } -func (suite *UtilTest) TestIsolateContextFromParentContext() { +func (ts *UtilTest) TestIsolateContextFromParentContext() { parentCtx, parentCtxCancel := context.WithCancel(context.Background()) // Call the method and cancel the parent context. @@ -273,8 +273,8 @@ func (suite *UtilTest) TestIsolateContextFromParentContext() { parentCtxCancel() // Validate new context is not cancelled after parent's cancellation. - assert.NoError(suite.T(), newCtx.Err()) + assert.NoError(ts.T(), newCtx.Err()) // Cancel the new context and validate. newCtxCancel() - assert.ErrorIs(suite.T(), newCtx.Err(), context.Canceled) + assert.ErrorIs(ts.T(), newCtx.Err(), context.Canceled) }