From fdd1b8ac5055f733ff0cc214f8db77af24a07157 Mon Sep 17 00:00:00 2001 From: Tulsishah <46474643+Tulsishah@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:28:12 +0530 Subject: [PATCH] Integration tests setup (#1013) * Integration tests * Integration tests lint fix * Integration tests lint fix * keeping only setup * making flags as 2D variable * adding getter setter for variable * formating the code * changing variable name * formating code * fixing comments * fixing lint test * fixing comments * fixing lint test * fixing lint test * fixing lint test * fixing comments --- .../implicitdir/file_operations_test.go | 21 +- .../implicitdir/implicitdir_test.go | 204 +-------------- .../implicitdir/read_test.go | 12 +- .../implicitdir/write_test.go | 18 +- tools/integration_tests/setup/setup.go | 242 ++++++++++++++++++ 5 files changed, 286 insertions(+), 211 deletions(-) create mode 100644 tools/integration_tests/setup/setup.go diff --git a/tools/integration_tests/implicitdir/file_operations_test.go b/tools/integration_tests/implicitdir/file_operations_test.go index 610811474f..48a1ab93fe 100644 --- a/tools/integration_tests/implicitdir/file_operations_test.go +++ b/tools/integration_tests/implicitdir/file_operations_test.go @@ -21,14 +21,17 @@ import ( "path" "testing" "time" + + "github.com/googlecloudplatform/gcsfuse/tools/integration_tests/setup" ) func TestRenameFile(t *testing.T) { - fileName := createTempFile() - err := clearKernelCache() + fileName := setup.CreateTempFile() + err := setup.ClearKernelCache() if err != nil { t.Errorf("Clear Kernel Cache: %v", err) } + content, err := os.ReadFile(fileName) if err != nil { t.Errorf("Read: %v", err) @@ -49,12 +52,12 @@ func TestRenameFile(t *testing.T) { t.Errorf("Renamed file %s not found", newFileName) } // Check if the data in the file is the same after renaming. - compareFileContents(t, newFileName, string(content)) + setup.CompareFileContents(t, newFileName, string(content)) } func TestFileAttributes(t *testing.T) { preCreateTime := time.Now() - fileName := createTempFile() + fileName := setup.CreateTempFile() postCreateTime := time.Now() fStat, err := os.Stat(fileName) @@ -62,7 +65,7 @@ func TestFileAttributes(t *testing.T) { if err != nil { t.Errorf("os.Stat error: %s, %v", fileName, err) } - statFileName := path.Join(tmpDir, fStat.Name()) + statFileName := path.Join(setup.TmpDir(), fStat.Name()) if fileName != statFileName { t.Errorf("File name not matched in os.Stat, found: %s, expected: %s", statFileName, fileName) } @@ -76,8 +79,8 @@ func TestFileAttributes(t *testing.T) { } func TestCopyFile(t *testing.T) { - fileName := createTempFile() - err := clearKernelCache() + fileName := setup.CreateTempFile() + err := setup.ClearKernelCache() if err != nil { t.Errorf("Clear Kernel Cache: %v", err) } @@ -108,6 +111,6 @@ func TestCopyFile(t *testing.T) { // Check if the data in the copied file matches the original file, // and the data in original file is unchanged. - compareFileContents(t, newFileName, string(content)) - compareFileContents(t, fileName, string(content)) + setup.CompareFileContents(t, newFileName, string(content)) + setup.CompareFileContents(t, fileName, string(content)) } diff --git a/tools/integration_tests/implicitdir/implicitdir_test.go b/tools/integration_tests/implicitdir/implicitdir_test.go index 3daa87c5ce..86a193caa7 100644 --- a/tools/integration_tests/implicitdir/implicitdir_test.go +++ b/tools/integration_tests/implicitdir/implicitdir_test.go @@ -16,221 +16,43 @@ package implicitdir_test import ( - "bytes" "flag" - "fmt" - "io/ioutil" "log" "os" - "os/exec" - "path" "testing" - "github.com/googlecloudplatform/gcsfuse/tools/util" + "github.com/googlecloudplatform/gcsfuse/tools/integration_tests/setup" ) -var testBucket = flag.String("testbucket", "", "The GCS bucket used for the test.") -var mountedDirectory = flag.String("mountedDirectory", "", "The GCSFuse mounted directory used for the test.") - -var ( - binFile string - logFile string - mntDir string - testDir string - tmpDir string -) - -func setUpTestDir() error { - var err error - testDir, err = ioutil.TempDir("", "gcsfuse_readwrite_test_") - if err != nil { - return fmt.Errorf("TempDir: %w\n", err) - } - - err = util.BuildGcsfuse(testDir) - if err != nil { - return fmt.Errorf("BuildGcsfuse(%q): %w\n", testDir, err) - } - - binFile = path.Join(testDir, "bin/gcsfuse") - logFile = path.Join(testDir, "gcsfuse.log") - mntDir = path.Join(testDir, "mnt") - - err = os.Mkdir(mntDir, 0755) - if err != nil { - return fmt.Errorf("Mkdir(%q): %v\n", mntDir, err) - } - return nil -} - -func mountGcsfuse(flag string) error { - mountCmd := exec.Command( - binFile, - "--debug_gcs", - "--debug_fs", - "--debug_fuse", - "--log-file="+logFile, - "--log-format=text", - flag, - *testBucket, - mntDir, - ) - - // Adding mount command in logFile - file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - fmt.Println("Could not open logfile") - } - defer file.Close() - - _, err = file.WriteString(mountCmd.String() + "\n") - if err != nil { - fmt.Println("Could not write cmd to logFile") - } - - output, err := mountCmd.CombinedOutput() - if err != nil { - log.Println(mountCmd.String()) - return fmt.Errorf("cannot mount gcsfuse: %w\n", err) - } - if lines := bytes.Count(output, []byte{'\n'}); lines > 1 { - return fmt.Errorf("mount output: %q\n", output) - } - return nil -} - -func unMount() error { - fusermount, err := exec.LookPath("fusermount") - if err != nil { - return fmt.Errorf("cannot find fusermount: %w", err) - } - cmd := exec.Command(fusermount, "-uz", mntDir) - if _, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("fusermount error: %w", err) - } - return nil -} - -func clearKernelCache() error { - if _, err := os.Stat("/proc/sys/vm/drop_caches"); err != nil { - log.Printf("Kernel cache file not found: %v", err) - // No need to stop the test execution if cache file is not found. Further - // reads will be served from kernel cache. - return nil - } - - // sudo permission is required to clear kernel page cache. - cmd := exec.Command("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches") - if err := cmd.Run(); err != nil { - return fmt.Errorf("clear kernel cache failed with error: %w", err) - } - return nil -} - -func compareFileContents(t *testing.T, fileName string, fileContent string) { - // After write, data will be cached by kernel. So subsequent read will be - // served using cached data by kernel instead of calling gcsfuse. - // Clearing kernel cache to ensure that gcsfuse is invoked during read operation. - err := clearKernelCache() - if err != nil { - t.Errorf("Clear Kernel Cache: %v", err) - } - - content, err := os.ReadFile(fileName) - if err != nil { - t.Errorf("Read: %v", err) - } - - if got := string(content); got != fileContent { - t.Errorf("File content doesn't match. Expected: %q, Actual: %q", got, fileContent) - } -} - -func logAndExit(s string) { - log.Print(s) - os.Exit(1) -} - -func createTempFile() string { - // A temporary file is created and some lines are added - // to it for testing purposes. - fileName := path.Join(tmpDir, "tmpFile") - err := os.WriteFile(fileName, []byte("line 1\nline 2\n"), 0666) - if err != nil { - logAndExit(fmt.Sprintf("Temporary file at %v", err)) - } - return fileName -} - -func executeTest(m *testing.M) (successCode int) { - // Creating a temporary directory to store files - // to be used for testing. - var err error - tmpDir, err = os.MkdirTemp(mntDir, "tmpDir") - if err != nil { - logAndExit(fmt.Sprintf("Mkdir at %q: %v", mntDir, err)) - } - - successCode = m.Run() - - os.RemoveAll(mntDir) - - return successCode -} - -func executeTestForFlags(flags []string, m *testing.M) (successCode int) { - var err error - for i := 0; i < len(flags); i++ { - if err = mountGcsfuse(flags[i]); err != nil { - logAndExit(fmt.Sprintf("mountGcsfuse: %v\n", err)) - } - - successCode = executeTest(m) - - err = unMount() - if err != nil { - logAndExit(fmt.Sprintf("Error in unmounting bucket: %v", err)) - } - - // Print flag on which test fails - if successCode != 0 { - log.Print("Test Fails on " + flags[i]) - return - } - - } - return -} - func TestMain(m *testing.M) { flag.Parse() - if *testBucket == "" && *mountedDirectory == "" { + if setup.TestBucket() == "" && setup.MountedDirectory() == "" { log.Printf("--testbucket or --mountedDirectory must be specified") os.Exit(0) - } else if *testBucket != "" && *mountedDirectory != "" { + } else if setup.TestBucket() != "" && setup.MountedDirectory() != "" { log.Printf("Both --testbucket and --mountedDirectory can't be specified at the same time.") os.Exit(0) } - if *mountedDirectory != "" { - mntDir = *mountedDirectory - successCode := executeTest(m) + if setup.MountedDirectory() != "" { + setup.SetMntDir(setup.MountedDirectory()) + successCode := setup.ExecuteTest(m) os.Exit(successCode) } - if err := setUpTestDir(); err != nil { + if err := setup.SetUpTestDir(); err != nil { log.Printf("setUpTestDir: %v\n", err) os.Exit(1) } - flags := []string{"--enable-storage-client-library=true", - "--enable-storage-client-library=false", - "--implicit-dirs=true", - "--implicit-dirs=false"} + flags := [][]string{{"--enable-storage-client-library=true", "--implicit-dirs=true"}, + {"--enable-storage-client-library=false"}, + {"--implicit-dirs=true"}, + {"--implicit-dirs=false"}} - successCode := executeTestForFlags(flags, m) + successCode := setup.ExecuteTestForFlags(flags, m) - log.Printf("Test log: %s\n", logFile) + log.Printf("Test log: %s\n", setup.LogFile()) os.Exit(successCode) } diff --git a/tools/integration_tests/implicitdir/read_test.go b/tools/integration_tests/implicitdir/read_test.go index 73a86413df..68d10333e5 100644 --- a/tools/integration_tests/implicitdir/read_test.go +++ b/tools/integration_tests/implicitdir/read_test.go @@ -19,12 +19,14 @@ import ( "io/ioutil" "os" "testing" + + "github.com/googlecloudplatform/gcsfuse/tools/integration_tests/setup" ) func TestReadAfterWrite(t *testing.T) { - tmpDir, err := ioutil.TempDir(mntDir, "tmpDir") + tmpDir, err := ioutil.TempDir(setup.MntDir(), "tmpDir") if err != nil { - t.Errorf("Mkdir at %q: %v", mntDir, err) + t.Errorf("Mkdir at %q: %v", setup.MntDir(), err) return } @@ -46,7 +48,11 @@ func TestReadAfterWrite(t *testing.T) { // After write, data will be cached by kernel. So subsequent read will be // served using cached data by kernel instead of calling gcsfuse. // Clearing kernel cache to ensure that gcsfuse is invoked during read operation. - clearKernelCache() + err = setup.ClearKernelCache() + if err != nil { + t.Errorf("Clear Kernel Cache: %v", err) + } + tmpFile, err = os.Open(fileName) if err != nil { t.Errorf("Open %q: %v", fileName, err) diff --git a/tools/integration_tests/implicitdir/write_test.go b/tools/integration_tests/implicitdir/write_test.go index 15c58943c1..d36d992ab3 100644 --- a/tools/integration_tests/implicitdir/write_test.go +++ b/tools/integration_tests/implicitdir/write_test.go @@ -18,10 +18,12 @@ package implicitdir_test import ( "os" "testing" + + "github.com/googlecloudplatform/gcsfuse/tools/integration_tests/setup" ) func TestWriteAtEndOfFile(t *testing.T) { - fileName := createTempFile() + fileName := setup.CreateTempFile() f, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, 0600) if err != nil { t.Errorf("Open file for append: %v", err) @@ -32,11 +34,11 @@ func TestWriteAtEndOfFile(t *testing.T) { } f.Close() - compareFileContents(t, fileName, "line 1\nline 2\nline 3\n") + setup.CompareFileContents(t, fileName, "line 1\nline 2\nline 3\n") } func TestWriteAtStartOfFile(t *testing.T) { - fileName := createTempFile() + fileName := setup.CreateTempFile() f, err := os.OpenFile(fileName, os.O_WRONLY, 0600) if err != nil { t.Errorf("Open file for write at start: %v", err) @@ -47,11 +49,11 @@ func TestWriteAtStartOfFile(t *testing.T) { } f.Close() - compareFileContents(t, fileName, "line 4\nline 2\n") + setup.CompareFileContents(t, fileName, "line 4\nline 2\n") } func TestWriteAtRandom(t *testing.T) { - fileName := createTempFile() + fileName := setup.CreateTempFile() f, err := os.OpenFile(fileName, os.O_WRONLY, 0600) if err != nil { @@ -65,16 +67,16 @@ func TestWriteAtRandom(t *testing.T) { } f.Close() - compareFileContents(t, fileName, "line 1\nline 5\n") + setup.CompareFileContents(t, fileName, "line 1\nline 5\n") } func TestCreateFile(t *testing.T) { - fileName := createTempFile() + fileName := setup.CreateTempFile() // Stat the file to check if it exists. if _, err := os.Stat(fileName); err != nil { t.Errorf("File not found, %v", err) } - compareFileContents(t, fileName, "line 1\nline 2\n") + setup.CompareFileContents(t, fileName, "line 1\nline 2\n") } diff --git a/tools/integration_tests/setup/setup.go b/tools/integration_tests/setup/setup.go new file mode 100644 index 0000000000..2d079518c2 --- /dev/null +++ b/tools/integration_tests/setup/setup.go @@ -0,0 +1,242 @@ +package setup + +import ( + "bytes" + "flag" + "fmt" + "log" + "os" + "os/exec" + "path" + "strings" + "testing" + + "github.com/googlecloudplatform/gcsfuse/tools/util" +) + +var testBucket = flag.String("testbucket", "", "The GCS bucket used for the test.") +var mountedDirectory = flag.String("mountedDirectory", "", "The GCSFuse mounted directory used for the test.") + +var ( + binFile string + logFile string + testDir string + tmpDir string + mntDir string +) + +func TestBucket() string { + return *testBucket +} + +func MountedDirectory() string { + return *mountedDirectory +} + +func SetLogFile(logFileValue string) { + logFile = logFileValue +} + +func LogFile() string { + return logFile +} + +func SetBinFile(binFileValue string) { + binFile = binFileValue +} + +func BinFile() string { + return binFile +} + +func SetTestDir(testDirValue string) { + testDir = testDirValue +} + +func TestDir() string { + return testDir +} + +func SetTmpDir(tmpDirValue string) { + tmpDir = tmpDirValue +} + +func TmpDir() string { + return tmpDir +} + +func SetMntDir(mntDirValue string) { + mntDir = mntDirValue +} + +func MntDir() string { + return mntDir +} + +func ClearKernelCache() error { + if _, err := os.Stat("/proc/sys/vm/drop_caches"); err != nil { + log.Printf("Kernel cache file not found: %v", err) + // No need to stop the test execution if cache file is not found. Further + // reads will be served from kernel cache. + return nil + } + + // sudo permission is required to clear kernel page cache. + cmd := exec.Command("sudo", "sh", "-c", "echo 3 > /proc/sys/vm/drop_caches") + if err := cmd.Run(); err != nil { + return fmt.Errorf("clear kernel cache failed with error: %w", err) + } + return nil +} + +func CompareFileContents(t *testing.T, fileName string, fileContent string) { + // After write, data will be cached by kernel. So subsequent read will be + // served using cached data by kernel instead of calling gcsfuse. + // Clearing kernel cache to ensure that gcsfuse is invoked during read operation. + err := ClearKernelCache() + if err != nil { + t.Errorf("Clear Kernel Cache: %v", err) + } + + content, err := os.ReadFile(fileName) + if err != nil { + t.Errorf("Read: %v", err) + } + + if got := string(content); got != fileContent { + t.Errorf("File content doesn't match. Expected: %q, Actual: %q", got, fileContent) + } +} + +func CreateTempFile() string { + // A temporary file is created and some lines are added + // to it for testing purposes. + fileName := path.Join(tmpDir, "tmpFile") + err := os.WriteFile(fileName, []byte("line 1\nline 2\n"), 0666) + if err != nil { + LogAndExit(fmt.Sprintf("Temporary file at %v", err)) + } + return fileName +} + +func SetUpTestDir() error { + var err error + testDir, err = os.MkdirTemp("", "gcsfuse_readwrite_test_") + if err != nil { + return fmt.Errorf("TempDir: %w\n", err) + } + + err = util.BuildGcsfuse(testDir) + if err != nil { + return fmt.Errorf("BuildGcsfuse(%q): %w\n", TestDir(), err) + } + + binFile = path.Join(TestDir(), "bin/gcsfuse") + logFile = path.Join(TestDir(), "gcsfuse.log") + mntDir = path.Join(TestDir(), "mnt") + + err = os.Mkdir(mntDir, 0755) + if err != nil { + return fmt.Errorf("Mkdir(%q): %v\n", MntDir(), err) + } + return nil +} + +func MountGcsfuse(flags []string) error { + defaultArg := []string{"--debug_gcs", + "--debug_fs", + "--debug_fuse", + "--log-file=" + LogFile(), + "--log-format=text", + *testBucket, + mntDir} + + for i := 0; i < len(defaultArg); i++ { + flags = append(flags, defaultArg[i]) + } + + mountCmd := exec.Command( + binFile, + flags..., + ) + + // Adding mount command in LogFile + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Println("Could not open logfile") + } + defer file.Close() + + _, err = file.WriteString(mountCmd.String() + "\n") + if err != nil { + fmt.Println("Could not write cmd to logFile") + } + + output, err := mountCmd.CombinedOutput() + if err != nil { + log.Println(mountCmd.String()) + return fmt.Errorf("cannot mount gcsfuse: %w\n", err) + } + if lines := bytes.Count(output, []byte{'\n'}); lines > 1 { + return fmt.Errorf("mount output: %q\n", output) + } + return nil +} + +func UnMount() error { + fusermount, err := exec.LookPath("fusermount") + if err != nil { + return fmt.Errorf("cannot find fusermount: %w", err) + } + cmd := exec.Command(fusermount, "-uz", mntDir) + if _, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("fusermount error: %w", err) + } + return nil +} + +func ExecuteTest(m *testing.M) (successCode int) { + // Creating a temporary directory to store files + // to be used for testing. + var err error + tmpDir, err = os.MkdirTemp(mntDir, "tmpDir") + if err != nil { + LogAndExit(fmt.Sprintf("Mkdir at %q: %v", MntDir(), err)) + } + successCode = m.Run() + + os.RemoveAll(mntDir) + + return successCode +} + +func ExecuteTestForFlags(flags [][]string, m *testing.M) (successCode int) { + var err error + + for i := 0; i < len(flags); i++ { + if err = MountGcsfuse(flags[i]); err != nil { + LogAndExit(fmt.Sprintf("mountGcsfuse: %v\n", err)) + } + + successCode = ExecuteTest(m) + + err = UnMount() + if err != nil { + LogAndExit(fmt.Sprintf("Error in unmounting bucket: %v", err)) + } + + // Print flag on which test fails + if successCode != 0 { + f := strings.Join(flags[i], " ") + log.Print("Test Fails on " + f) + return + } + + } + return +} + +func LogAndExit(s string) { + log.Print(s) + os.Exit(1) +}