Skip to content

Commit 338ee35

Browse files
authored
refactor: stale file test package migration [GKE-GCSFuse Test migration] (#3884)
* rebasing? * stale file handle pckg update 23oct * rebase and minor change * make 2 suites instead of 4 * skip mounted dir tests
1 parent a6ed753 commit 338ee35

6 files changed

Lines changed: 177 additions & 126 deletions

File tree

tools/integration_tests/stale_handle/setup_test.go

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
// you may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at
66
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
7+
// http://www.apache.org/licenses/LICENSE-2.0
88
//
99
// Unless required by applicable law or agreed to in writing, software
1010
// distributed under the License is distributed on an "AS IS" BASIS,
1111
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
14-
1514
package stale_handle
1615

1716
import (
@@ -24,60 +23,92 @@ import (
2423
"github.com/googlecloudplatform/gcsfuse/v3/tools/integration_tests/util/client"
2524
"github.com/googlecloudplatform/gcsfuse/v3/tools/integration_tests/util/mounting/static_mounting"
2625
"github.com/googlecloudplatform/gcsfuse/v3/tools/integration_tests/util/setup"
26+
"github.com/googlecloudplatform/gcsfuse/v3/tools/integration_tests/util/test_suite"
2727
)
2828

2929
const (
3030
testDirName = "StaleHandleTest"
3131
)
3232

3333
var (
34+
testEnv env
35+
mountFunc func(*test_suite.TestConfig, []string) error
36+
// mount directory is where our tests run.
37+
mountDir string
38+
)
39+
40+
type env struct {
3441
storageClient *storage.Client
3542
ctx context.Context
36-
rootDir string
37-
mountFunc func([]string) error
38-
flagsSet [][]string
39-
)
43+
testDirPath string
44+
cfg *test_suite.TestConfig
45+
bucketType string
46+
}
4047

4148
////////////////////////////////////////////////////////////////////////
4249
// TestMain
4350
////////////////////////////////////////////////////////////////////////
4451

4552
func TestMain(m *testing.M) {
4653
setup.ParseSetUpFlags()
47-
setup.ExitWithFailureIfBothTestBucketAndMountedDirectoryFlagsAreNotSet()
4854

49-
// Create common storage client to be used in test.
50-
ctx = context.Background()
51-
closeStorageClient := client.CreateStorageClientWithCancel(&ctx, &storageClient)
52-
defer func() {
53-
err := closeStorageClient()
54-
if err != nil {
55-
log.Fatalf("closeStorageClient failed: %v", err)
55+
// 1. Load and parse the common configuration.
56+
cfg := test_suite.ReadConfigFile(setup.ConfigFile())
57+
if len(cfg.StaleHandle) == 0 {
58+
log.Println("No configuration found for stale_handle tests in config. Using flags instead.")
59+
if setup.MountedDirectory() != "" {
60+
log.Println("Skip mounted directory tests if no config file has been passed.")
61+
os.Exit(0)
62+
}
63+
// Populate the config manually.
64+
cfg.StaleHandle = make([]test_suite.TestConfig, 1)
65+
cfg.StaleHandle[0].TestBucket = setup.TestBucket()
66+
cfg.StaleHandle[0].GKEMountedDirectory = setup.MountedDirectory()
67+
cfg.StaleHandle[0].LogFile = setup.LogFile()
68+
cfg.StaleHandle[0].Configs = make([]test_suite.ConfigItem, 4)
69+
cfg.StaleHandle[0].Configs[0].Flags = []string{
70+
"--metadata-cache-ttl-secs=0 --write-block-size-mb=1 --write-max-blocks-per-file=1",
71+
"--metadata-cache-ttl-secs=0 --write-block-size-mb=1 --write-max-blocks-per-file=1 --client-protocol=grpc",
5672
}
57-
}()
73+
cfg.StaleHandle[0].Configs[0].Compatible = map[string]bool{"flat": true, "hns": true, "zonal": true}
74+
cfg.StaleHandle[0].Configs[0].Run = "TestStaleHandleStreamingWritesEnabled"
5875

59-
// To run mountedDirectory tests, we need both testBucket and mountedDirectory
60-
// flags to be set, as stale handle tests validates content from the bucket.
61-
// Note: These tests by default can only be run for non streaming mounts.
62-
if setup.AreBothMountedDirectoryAndTestBucketFlagsSet() {
63-
rootDir = setup.MountedDirectory()
64-
setup.RunTestsForMountedDirectoryFlag(m)
65-
return
76+
cfg.StaleHandle[0].Configs[1].Flags = []string{
77+
"--metadata-cache-ttl-secs=0 --enable-streaming-writes=false",
78+
"--metadata-cache-ttl-secs=0 --enable-streaming-writes=false --client-protocol=grpc",
79+
}
80+
cfg.StaleHandle[0].Configs[1].Compatible = map[string]bool{"flat": true, "hns": true, "zonal": true}
81+
cfg.StaleHandle[0].Configs[1].Run = "TestStaleHandleStreamingWritesDisabled"
6682
}
6783

68-
// Set up test directory.
69-
setup.SetUpTestDirForTestBucketFlag()
70-
rootDir = setup.MntDir()
84+
testEnv.ctx = context.Background()
85+
testEnv.cfg = &cfg.StaleHandle[0]
86+
testEnv.bucketType = setup.TestEnvironment(testEnv.ctx, testEnv.cfg)
7187

72-
flagsSet = [][]string{
73-
{"--metadata-cache-ttl-secs=0", "--enable-streaming-writes=false"},
74-
{"--metadata-cache-ttl-secs=0", "--write-block-size-mb=1", "--write-max-blocks-per-file=1"},
88+
// 2. Create storage client before running tests.
89+
var err error
90+
testEnv.storageClient, err = client.CreateStorageClient(testEnv.ctx)
91+
if err != nil {
92+
log.Printf("Error creating storage client: %v\n", err)
93+
os.Exit(1)
7594
}
76-
// Run all tests with GRPC.
77-
setup.AppendFlagsToAllFlagsInTheFlagsSet(&flagsSet, "--client-protocol=grpc", "")
95+
defer testEnv.storageClient.Close()
96+
97+
// 3. To run mountedDirectory tests, we need both testBucket and mountedDirectory
98+
// flags to be set, as stale handle tests validates content from the bucket.
99+
// Note: These tests by default can only be run for non streaming mounts.
100+
if testEnv.cfg.GKEMountedDirectory != "" && testEnv.cfg.TestBucket != "" {
101+
mountDir = testEnv.cfg.GKEMountedDirectory
102+
os.Exit(setup.RunTestsForMountedDirectory(testEnv.cfg.GKEMountedDirectory, m))
103+
}
104+
105+
// Run tests for testBucket
106+
setup.SetUpTestDirForTestBucket(testEnv.cfg)
107+
mountDir = setup.MntDir()
78108

79109
log.Println("Running static mounting tests...")
80-
mountFunc = static_mounting.MountGcsfuseWithStaticMounting
110+
mountFunc = static_mounting.MountGcsfuseWithStaticMountingWithConfigFile
81111
successCode := m.Run()
112+
82113
os.Exit(successCode)
83114
}

tools/integration_tests/stale_handle/stale_file_handle_common_test.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// you may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at
66
//
7-
//http://www.apache.org/licenses/LICENSE-2.0
7+
// http://www.apache.org/licenses/LICENSE-2.0
88
//
99
// Unless required by applicable law or agreed to in writing, software
1010
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -33,28 +33,26 @@ import (
3333
// //////////////////////////////////////////////////////////////////////
3434

3535
type staleFileHandleCommon struct {
36+
suite.Suite
3637
flags []string
3738
f1 *os.File
3839
fileName string
3940
data string
40-
testDirPath string
4141
isStreamingWritesEnabled bool
4242
isLocal bool
43-
suite.Suite
4443
}
4544

46-
// //////////////////////////////////////////////////////////////////////
47-
// Helpers
48-
// //////////////////////////////////////////////////////////////////////
4945
func (s *staleFileHandleCommon) SetupSuite() {
50-
setup.MountGCSFuseWithGivenMountFunc(s.flags, mountFunc)
51-
s.testDirPath = setup.SetupTestDirectory(testDirName)
46+
setup.MountGCSFuseWithGivenMountWithConfigFunc(testEnv.cfg, s.flags, mountFunc)
47+
if testEnv.cfg.GKEMountedDirectory == "" {
48+
setup.SetMntDir(testEnv.cfg.GCSFuseMountedDirectory)
49+
}
50+
testEnv.testDirPath = SetupTestDirectory(testEnv.ctx, testEnv.storageClient, testDirName)
5251
s.data = setup.GenerateRandomString(5 * util.MiB)
5352
}
5453

5554
func (s *staleFileHandleCommon) TearDownSuite() {
56-
setup.UnmountGCSFuse(rootDir)
57-
setup.SaveGCSFuseLogFileInCaseOfFailure(s.T())
55+
setup.UnmountGCSFuseWithConfig(testEnv.cfg)
5856
}
5957

6058
////////////////////////////////////////////////////////////////////////
@@ -69,13 +67,14 @@ func (s *staleFileHandleCommon) TestClobberedFileSyncAndCloseThrowsStaleFileHand
6967
// Dirty the file by giving it some contents.
7068
operations.WriteWithoutClose(s.f1, s.data, s.T())
7169
// Clobber file by replacing the underlying object with a new generation.
72-
err := WriteToObject(ctx, storageClient, path.Join(testDirName, s.fileName), FileContents, storage.Conditions{})
70+
err := WriteToObject(testEnv.ctx, testEnv.storageClient, path.Join(testDirName, s.fileName), FileContents, storage.Conditions{})
7371
assert.NoError(s.T(), err)
7472

7573
operations.ValidateSyncGivenThatFileIsClobbered(s.T(), s.f1, s.isStreamingWritesEnabled)
74+
7675
err = s.f1.Close()
7776
operations.ValidateESTALEError(s.T(), err)
78-
ValidateObjectContentsFromGCS(ctx, storageClient, testDirName, s.fileName, FileContents, s.T())
77+
ValidateObjectContentsFromGCS(testEnv.ctx, testEnv.storageClient, testDirName, s.fileName, FileContents, s.T())
7978
}
8079

8180
func (s *staleFileHandleCommon) TestFileDeletedLocallySyncAndCloseDoNotThrowError() {
@@ -91,7 +90,7 @@ func (s *staleFileHandleCommon) TestFileDeletedLocallySyncAndCloseDoNotThrowErro
9190
operations.WriteWithoutClose(s.f1, s.data, s.T())
9291
operations.SyncFile(s.f1, s.T())
9392
operations.CloseFileShouldNotThrowError(s.T(), s.f1)
94-
ValidateObjectNotFoundErrOnGCS(ctx, storageClient, testDirName, s.fileName, s.T())
93+
ValidateObjectNotFoundErrOnGCS(testEnv.ctx, testEnv.storageClient, testDirName, s.fileName, s.T())
9594
}
9695

9796
func (s *staleFileHandleCommon) TestRenamedFileSyncAndCloseThrowsStaleFileHandleError() {
@@ -100,7 +99,7 @@ func (s *staleFileHandleCommon) TestRenamedFileSyncAndCloseThrowsStaleFileHandle
10099
assert.NoError(s.T(), err)
101100
newFile := "new" + s.fileName
102101

103-
err = operations.RenameFile(s.f1.Name(), path.Join(s.testDirPath, newFile))
102+
err = operations.RenameFile(s.f1.Name(), path.Join(testEnv.testDirPath, newFile))
104103

105104
assert.NoError(s.T(), err)
106105
_, err = s.f1.WriteString(s.data)

tools/integration_tests/stale_handle/stale_file_handle_synced_file_test.go renamed to tools/integration_tests/stale_handle/stale_file_handle_local_and_synced_file_test.go

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
package stale_handle
1616

1717
import (
18+
"log"
1819
"path"
19-
"slices"
2020
"testing"
2121

2222
"cloud.google.com/go/storage"
@@ -30,6 +30,9 @@ import (
3030
// //////////////////////////////////////////////////////////////////////
3131
// Boilerplate
3232
// //////////////////////////////////////////////////////////////////////
33+
type staleFileHandleLocalFile struct {
34+
staleFileHandleCommon
35+
}
3336

3437
type staleFileHandleEmptyGcsFile struct {
3538
staleFileHandleCommon
@@ -39,12 +42,24 @@ type staleFileHandleEmptyGcsFile struct {
3942
// Helpers
4043
// //////////////////////////////////////////////////////////////////////
4144

45+
func (s *staleFileHandleLocalFile) SetupTest() {
46+
// Create a local file.
47+
s.fileName = path.Base(s.T().Name()) + setup.GenerateRandomString(5)
48+
s.f1 = operations.OpenFileWithODirect(s.T(), path.Join(testEnv.testDirPath, s.fileName))
49+
s.isLocal = true
50+
}
51+
func (s *staleFileHandleLocalFile) TearDownTest() {
52+
setup.SaveGCSFuseLogFileInCaseOfFailure(s.T())
53+
}
54+
4255
func (s *staleFileHandleEmptyGcsFile) SetupTest() {
43-
// Create an empty object on GCS.
4456
s.fileName = path.Base(s.T().Name()) + setup.GenerateRandomString(5)
45-
err := CreateObjectOnGCS(ctx, storageClient, path.Join(testDirName, s.fileName), "")
57+
err := CreateObjectOnGCS(testEnv.ctx, testEnv.storageClient, path.Join(testDirName, s.fileName), "")
4658
assert.NoError(s.T(), err)
47-
s.f1 = operations.OpenFileWithODirect(s.T(), path.Join(s.testDirPath, s.fileName))
59+
s.f1 = operations.OpenFileWithODirect(s.T(), path.Join(testEnv.testDirPath, s.fileName))
60+
}
61+
func (s *staleFileHandleEmptyGcsFile) TearDownTest() {
62+
setup.SaveGCSFuseLogFileInCaseOfFailure(s.T())
4863
}
4964

5065
////////////////////////////////////////////////////////////////////////
@@ -62,7 +77,7 @@ func (s *staleFileHandleEmptyGcsFile) TestClobberedFileReadThrowsStaleFileHandle
6277
operations.SyncFile(s.f1, s.T())
6378

6479
// Replace the underlying object with a new generation.
65-
err = WriteToObject(ctx, storageClient, path.Join(testDirName, s.fileName), FileContents, storage.Conditions{})
80+
err = WriteToObject(testEnv.ctx, testEnv.storageClient, path.Join(testDirName, s.fileName), FileContents, storage.Conditions{})
6681

6782
assert.NoError(s.T(), err)
6883
buffer := make([]byte, len(s.data))
@@ -76,7 +91,7 @@ func (s *staleFileHandleEmptyGcsFile) TestClobberedFileFirstWriteThrowsStaleFile
7691
s.T().Skip("Skip test due to takeover support not available.")
7792
}
7893
// Clobber file by replacing the underlying object with a new generation.
79-
err := WriteToObject(ctx, storageClient, path.Join(testDirName, s.fileName), FileContents, storage.Conditions{})
94+
err := WriteToObject(testEnv.ctx, testEnv.storageClient, path.Join(testDirName, s.fileName), FileContents, storage.Conditions{})
8095
assert.NoError(s.T(), err)
8196

8297
// Attempt first write to the file should give stale NFS file handle error.
@@ -86,7 +101,7 @@ func (s *staleFileHandleEmptyGcsFile) TestClobberedFileFirstWriteThrowsStaleFile
86101
operations.ValidateSyncGivenThatFileIsClobbered(s.T(), s.f1, s.isStreamingWritesEnabled)
87102
err = s.f1.Close()
88103
operations.ValidateESTALEError(s.T(), err)
89-
ValidateObjectContentsFromGCS(ctx, storageClient, testDirName, s.fileName, FileContents, s.T())
104+
ValidateObjectContentsFromGCS(testEnv.ctx, testEnv.storageClient, testDirName, s.fileName, FileContents, s.T())
90105
}
91106

92107
func (s *staleFileHandleEmptyGcsFile) TestFileDeletedRemotelySyncAndCloseThrowsStaleFileHandleError() {
@@ -97,34 +112,80 @@ func (s *staleFileHandleEmptyGcsFile) TestFileDeletedRemotelySyncAndCloseThrowsS
97112
// Dirty the file by giving it some contents.
98113
operations.WriteWithoutClose(s.f1, s.data, s.T())
99114
// Delete the file remotely.
100-
err := DeleteObjectOnGCS(ctx, storageClient, path.Join(testDirName, s.fileName))
115+
err := DeleteObjectOnGCS(testEnv.ctx, testEnv.storageClient, path.Join(testDirName, s.fileName))
101116
assert.NoError(s.T(), err)
102117
// Verify unlink operation succeeds.
103-
ValidateObjectNotFoundErrOnGCS(ctx, storageClient, testDirName, s.fileName, s.T())
118+
ValidateObjectNotFoundErrOnGCS(testEnv.ctx, testEnv.storageClient, testDirName, s.fileName, s.T())
104119
// Attempt to write to file should not give any error.
105120
operations.WriteWithoutClose(s.f1, s.data, s.T())
106121

107122
operations.ValidateSyncGivenThatFileIsClobbered(s.T(), s.f1, s.isStreamingWritesEnabled)
108123

109124
err = s.f1.Close()
110125
operations.ValidateESTALEError(s.T(), err)
111-
ValidateObjectNotFoundErrOnGCS(ctx, storageClient, testDirName, s.fileName, s.T())
126+
ValidateObjectNotFoundErrOnGCS(testEnv.ctx, testEnv.storageClient, testDirName, s.fileName, s.T())
112127
}
113128

114129
////////////////////////////////////////////////////////////////////////
115130
// Test Function (Runs once before all tests)
116131
////////////////////////////////////////////////////////////////////////
117132

118-
func TestStaleFileHandleEmptyGcsFileTest(t *testing.T) {
133+
func TestStaleHandleStreamingWritesEnabled(t *testing.T) {
119134
// Run tests for mounted directory if the flag is set and return.
120135
if setup.AreBothMountedDirectoryAndTestBucketFlagsSet() {
121-
suite.Run(t, new(staleFileHandleEmptyGcsFile))
136+
// Run tests for local file.
137+
suite.Run(t, &staleFileHandleLocalFile{staleFileHandleCommon{isStreamingWritesEnabled: true}})
138+
139+
// Run tests for empty gcs file.
140+
suite.Run(t, &staleFileHandleEmptyGcsFile{staleFileHandleCommon{isStreamingWritesEnabled: true}})
141+
122142
return
123143
}
144+
145+
flagsSet := setup.BuildFlagSets(*testEnv.cfg, testEnv.bucketType, t.Name())
146+
for _, flags := range flagsSet {
147+
// Run local file tests
148+
sLocal := new(staleFileHandleLocalFile)
149+
sLocal.flags = flags
150+
log.Printf("Running local file tests with flags: %s", sLocal.flags)
151+
sLocal.isStreamingWritesEnabled = true
152+
suite.Run(t, sLocal)
153+
154+
// Run empty GCS file tests
155+
sEmptyGCS := new(staleFileHandleEmptyGcsFile)
156+
sEmptyGCS.flags = flags
157+
log.Printf("Running empty GCS file tests with flags: %s", sEmptyGCS.flags)
158+
sEmptyGCS.isStreamingWritesEnabled = true
159+
suite.Run(t, sEmptyGCS)
160+
}
161+
}
162+
163+
func TestStaleHandleStreamingWritesDisabled(t *testing.T) {
164+
// Run tests for mounted directory if the flag is set and return.
165+
if setup.AreBothMountedDirectoryAndTestBucketFlagsSet() {
166+
// Run tests for local file.
167+
suite.Run(t, &staleFileHandleLocalFile{staleFileHandleCommon{isStreamingWritesEnabled: false}})
168+
169+
// Run tests for empty gcs file.
170+
suite.Run(t, &staleFileHandleEmptyGcsFile{staleFileHandleCommon{isStreamingWritesEnabled: false}})
171+
172+
return
173+
}
174+
175+
flagsSet := setup.BuildFlagSets(*testEnv.cfg, testEnv.bucketType, t.Name())
124176
for _, flags := range flagsSet {
125-
s := new(staleFileHandleEmptyGcsFile)
126-
s.flags = flags
127-
s.isStreamingWritesEnabled = !slices.Contains(s.flags, "--enable-streaming-writes=false")
128-
suite.Run(t, s)
177+
// Run local file tests
178+
sLocal := new(staleFileHandleLocalFile)
179+
sLocal.flags = flags
180+
log.Printf("Running local file tests with flags: %s", sLocal.flags)
181+
sLocal.isStreamingWritesEnabled = false
182+
suite.Run(t, sLocal)
183+
184+
// Run empty GCS file tests
185+
sEmptyGCS := new(staleFileHandleEmptyGcsFile)
186+
sEmptyGCS.flags = flags
187+
log.Printf("Running empty GCS file tests with flags: %s", sEmptyGCS.flags)
188+
sEmptyGCS.isStreamingWritesEnabled = false
189+
suite.Run(t, sEmptyGCS)
129190
}
130191
}

0 commit comments

Comments
 (0)