From 247f90c82e0846ec108a4abab51af93fa14b86a1 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 26 Jan 2022 14:44:54 +0100 Subject: [PATCH 1/7] pkg/system: move maxTime init() back to Chtimes code This code was moved to a separate file in fe5b34ba8828dc2f2f7db180a102cee360fec6e0, but it's unclear why it was moved (as this file is not excluded on Windows). Moving the code back into the chtimes file, to move it closer to where it's used. Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes.go | 16 ++++++++++++++++ pkg/system/init.go | 22 ---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) delete mode 100644 pkg/system/init.go diff --git a/pkg/system/chtimes.go b/pkg/system/chtimes.go index c26a4e24b6..7cd751f089 100644 --- a/pkg/system/chtimes.go +++ b/pkg/system/chtimes.go @@ -2,9 +2,25 @@ package system // import "github.com/docker/docker/pkg/system" import ( "os" + "syscall" "time" + "unsafe" ) +// Used by Chtimes +var maxTime time.Time + +func init() { + if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { + // This is a 64 bit timespec + // os.Chtimes limits time to the following + maxTime = time.Unix(0, 1<<63-1) + } else { + // This is a 32 bit timespec + maxTime = time.Unix(1<<31-1, 0) + } +} + // Chtimes changes the access time and modified time of a file at the given path func Chtimes(name string, atime time.Time, mtime time.Time) error { unixMinTime := time.Unix(0, 0) diff --git a/pkg/system/init.go b/pkg/system/init.go deleted file mode 100644 index a17597aaba..0000000000 --- a/pkg/system/init.go +++ /dev/null @@ -1,22 +0,0 @@ -package system // import "github.com/docker/docker/pkg/system" - -import ( - "syscall" - "time" - "unsafe" -) - -// Used by chtimes -var maxTime time.Time - -func init() { - // chtimes initialization - if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { - // This is a 64 bit timespec - // os.Chtimes limits time to the following - maxTime = time.Unix(0, 1<<63-1) - } else { - // This is a 32 bit timespec - maxTime = time.Unix(1<<31-1, 0) - } -} From 2c9684e35c25c4d54d9904999990b67e24ac1da5 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 26 Jan 2022 15:36:49 +0100 Subject: [PATCH 2/7] pkg/system: add note about maxTime This code caused me some head-scratches, and initially I wondered if this was a bug, but it looks to be intentional to set nsec, not sec, as time.Unix() internally divides nsec, and sets sec accordingly; https://github.com/golang/go/blob/go1.19.2/src/time/time.go#L1364-L1380 // Unix returns the local Time corresponding to the given Unix time, // sec seconds and nsec nanoseconds since January 1, 1970 UTC. // It is valid to pass nsec outside the range [0, 999999999]. // Not all sec values have a corresponding time value. One such // value is 1<<63-1 (the largest int64 value). func Unix(sec int64, nsec int64) Time { if nsec < 0 || nsec >= 1e9 { n := nsec / 1e9 sec += n nsec -= n * 1e9 if nsec < 0 { nsec += 1e9 sec-- } } return unixTime(sec, int32(nsec)) } Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/system/chtimes.go b/pkg/system/chtimes.go index 7cd751f089..537ddadc63 100644 --- a/pkg/system/chtimes.go +++ b/pkg/system/chtimes.go @@ -14,6 +14,10 @@ func init() { if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { // This is a 64 bit timespec // os.Chtimes limits time to the following + // + // Note that this intentionally sets nsec (not sec), which sets both sec + // and nsec internally in time.Unix(); + // https://github.com/golang/go/blob/go1.19.2/src/time/time.go#L1364-L1380 maxTime = time.Unix(0, 1<<63-1) } else { // This is a 32 bit timespec From 0b8444aa0c3398cccab7bbc706205cd5effba6f5 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 7 Oct 2022 14:06:47 +0200 Subject: [PATCH 3/7] pkg/system: rename maxTime and re-use, define unixEpochTime, update GoDoc This more closely matches to how it's used everywhere. Also move the comment describing "what" ChTimes() does inside its GoDoc. Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes.go | 27 ++++++++++++--------------- pkg/system/chtimes_linux_test.go | 6 ++---- pkg/system/chtimes_test.go | 6 ++---- pkg/system/chtimes_windows_test.go | 6 ++---- 4 files changed, 18 insertions(+), 27 deletions(-) diff --git a/pkg/system/chtimes.go b/pkg/system/chtimes.go index 537ddadc63..6a6bca43ed 100644 --- a/pkg/system/chtimes.go +++ b/pkg/system/chtimes.go @@ -8,9 +8,10 @@ import ( ) // Used by Chtimes -var maxTime time.Time +var unixEpochTime, unixMaxTime time.Time func init() { + unixEpochTime = time.Unix(0, 0) if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { // This is a 64 bit timespec // os.Chtimes limits time to the following @@ -18,28 +19,24 @@ func init() { // Note that this intentionally sets nsec (not sec), which sets both sec // and nsec internally in time.Unix(); // https://github.com/golang/go/blob/go1.19.2/src/time/time.go#L1364-L1380 - maxTime = time.Unix(0, 1<<63-1) + unixMaxTime = time.Unix(0, 1<<63-1) } else { // This is a 32 bit timespec - maxTime = time.Unix(1<<31-1, 0) + unixMaxTime = time.Unix(1<<31-1, 0) } } -// Chtimes changes the access time and modified time of a file at the given path +// Chtimes changes the access time and modified time of a file at the given path. +// If the modified time is prior to the Unix Epoch (unixMinTime), or after the +// end of Unix Time (unixEpochTime), os.Chtimes has undefined behavior. In this +// case, Chtimes defaults to Unix Epoch, just in case. func Chtimes(name string, atime time.Time, mtime time.Time) error { - unixMinTime := time.Unix(0, 0) - unixMaxTime := maxTime - - // If the modified time is prior to the Unix Epoch, or after the - // end of Unix Time, os.Chtimes has undefined behavior - // default to Unix Epoch in this case, just in case - - if atime.Before(unixMinTime) || atime.After(unixMaxTime) { - atime = unixMinTime + if atime.Before(unixEpochTime) || atime.After(unixMaxTime) { + atime = unixEpochTime } - if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) { - mtime = unixMinTime + if mtime.Before(unixEpochTime) || mtime.After(unixMaxTime) { + mtime = unixEpochTime } if err := os.Chtimes(name, atime, mtime); err != nil { diff --git a/pkg/system/chtimes_linux_test.go b/pkg/system/chtimes_linux_test.go index 97f860443c..5235fb7895 100644 --- a/pkg/system/chtimes_linux_test.go +++ b/pkg/system/chtimes_linux_test.go @@ -12,10 +12,8 @@ func TestChtimesLinux(t *testing.T) { file, dir := prepareTempFile(t) defer os.RemoveAll(dir) - beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second) - unixEpochTime := time.Unix(0, 0) - afterUnixEpochTime := time.Unix(100, 0) - unixMaxTime := maxTime + beforeUnixEpochTime := unixEpochTime.Add(-100 * time.Second) + afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) // Test both aTime and mTime set to Unix Epoch Chtimes(file, unixEpochTime, unixEpochTime) diff --git a/pkg/system/chtimes_test.go b/pkg/system/chtimes_test.go index 3bb1fb2a60..5b634cccff 100644 --- a/pkg/system/chtimes_test.go +++ b/pkg/system/chtimes_test.go @@ -26,10 +26,8 @@ func TestChtimes(t *testing.T) { file, dir := prepareTempFile(t) defer os.RemoveAll(dir) - beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second) - unixEpochTime := time.Unix(0, 0) - afterUnixEpochTime := time.Unix(100, 0) - unixMaxTime := maxTime + beforeUnixEpochTime := unixEpochTime.Add(-100 * time.Second) + afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) // Test both aTime and mTime set to Unix Epoch Chtimes(file, unixEpochTime, unixEpochTime) diff --git a/pkg/system/chtimes_windows_test.go b/pkg/system/chtimes_windows_test.go index 060c515003..2461414079 100644 --- a/pkg/system/chtimes_windows_test.go +++ b/pkg/system/chtimes_windows_test.go @@ -15,10 +15,8 @@ func TestChtimesWindows(t *testing.T) { file, dir := prepareTempFile(t) defer os.RemoveAll(dir) - beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second) - unixEpochTime := time.Unix(0, 0) - afterUnixEpochTime := time.Unix(100, 0) - unixMaxTime := maxTime + beforeUnixEpochTime := unixEpochTime.Add(-100 * time.Second) + afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) // Test both aTime and mTime set to Unix Epoch Chtimes(file, unixEpochTime, unixEpochTime) From 7bd051eeec5a3ae35fe3bc8f126f48b2dbc858ac Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 7 Oct 2022 14:29:11 +0200 Subject: [PATCH 4/7] pkg/system: windows: setCTime(): remove redundant conversion It looks like this function was converting the time (`windows.NsecToTimespec()`), only to convert it back (`windows.TimespecToNsec()`). This became clear when moving the lines together: ```go ctimespec := windows.NsecToTimespec(ctime.UnixNano()) c := windows.NsecToFiletime(windows.TimespecToNsec(ctimespec)) ``` And looking at the Golang code, it looks like they're indeed the exact reverse: ```go func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } func NsecToTimespec(nsec int64) (ts Timespec) { ts.Sec = nsec / 1e9 ts.Nsec = nsec % 1e9 return } ``` While modifying this code, also renaming the `e` variable to a more common `err`. Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes_windows.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pkg/system/chtimes_windows.go b/pkg/system/chtimes_windows.go index 6664b8bcad..ab478f5c38 100644 --- a/pkg/system/chtimes_windows.go +++ b/pkg/system/chtimes_windows.go @@ -9,18 +9,17 @@ import ( // setCTime will set the create time on a file. On Windows, this requires // calling SetFileTime and explicitly including the create time. func setCTime(path string, ctime time.Time) error { - ctimespec := windows.NsecToTimespec(ctime.UnixNano()) - pathp, e := windows.UTF16PtrFromString(path) - if e != nil { - return e + pathp, err := windows.UTF16PtrFromString(path) + if err != nil { + return err } - h, e := windows.CreateFile(pathp, + h, err := windows.CreateFile(pathp, windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0) - if e != nil { - return e + if err != nil { + return err } defer windows.Close(h) - c := windows.NsecToFiletime(windows.TimespecToNsec(ctimespec)) + c := windows.NsecToFiletime(ctime.UnixNano()) return windows.SetFileTime(h, &c, nil, nil) } From ab7bc6b7d26635da87f2d67afc4256c93255b730 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 7 Oct 2022 15:44:50 +0200 Subject: [PATCH 5/7] pkg/system: use t.TempDir(), remove some test-utils With t.TempDir(), some of the test-utilities became so small that it was more transparent to inline them. This also helps separating concenrs, as we're in the process of thinning out and decoupling some packages. Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes_linux_test.go | 7 +++++-- pkg/system/chtimes_test.go | 20 ++++---------------- pkg/system/chtimes_windows_test.go | 7 +++++-- pkg/system/lstat_unix_test.go | 10 +++++++--- pkg/system/stat_unix_test.go | 7 +++++-- pkg/system/utimes_unix_test.go | 24 ++++++++++-------------- 6 files changed, 36 insertions(+), 39 deletions(-) diff --git a/pkg/system/chtimes_linux_test.go b/pkg/system/chtimes_linux_test.go index 5235fb7895..4f3d7eac6d 100644 --- a/pkg/system/chtimes_linux_test.go +++ b/pkg/system/chtimes_linux_test.go @@ -2,6 +2,7 @@ package system // import "github.com/docker/docker/pkg/system" import ( "os" + "path/filepath" "syscall" "testing" "time" @@ -9,8 +10,10 @@ import ( // TestChtimesLinux tests Chtimes access time on a tempfile on Linux func TestChtimesLinux(t *testing.T) { - file, dir := prepareTempFile(t) - defer os.RemoveAll(dir) + file := filepath.Join(t.TempDir(), "exist") + if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { + t.Fatal(err) + } beforeUnixEpochTime := unixEpochTime.Add(-100 * time.Second) afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) diff --git a/pkg/system/chtimes_test.go b/pkg/system/chtimes_test.go index 5b634cccff..020c8806fb 100644 --- a/pkg/system/chtimes_test.go +++ b/pkg/system/chtimes_test.go @@ -7,24 +7,12 @@ import ( "time" ) -// prepareTempFile creates a temporary file in a temporary directory. -func prepareTempFile(t *testing.T) (string, string) { - dir, err := os.MkdirTemp("", "docker-system-test") - if err != nil { - t.Fatal(err) - } - - file := filepath.Join(dir, "exist") - if err := os.WriteFile(file, []byte("hello"), 0644); err != nil { - t.Fatal(err) - } - return file, dir -} - // TestChtimes tests Chtimes on a tempfile. Test only mTime, because aTime is OS dependent func TestChtimes(t *testing.T) { - file, dir := prepareTempFile(t) - defer os.RemoveAll(dir) + file := filepath.Join(t.TempDir(), "exist") + if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { + t.Fatal(err) + } beforeUnixEpochTime := unixEpochTime.Add(-100 * time.Second) afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) diff --git a/pkg/system/chtimes_windows_test.go b/pkg/system/chtimes_windows_test.go index 2461414079..5c05e8e905 100644 --- a/pkg/system/chtimes_windows_test.go +++ b/pkg/system/chtimes_windows_test.go @@ -5,6 +5,7 @@ package system // import "github.com/docker/docker/pkg/system" import ( "os" + "path/filepath" "syscall" "testing" "time" @@ -12,8 +13,10 @@ import ( // TestChtimesWindows tests Chtimes access time on a tempfile on Windows func TestChtimesWindows(t *testing.T) { - file, dir := prepareTempFile(t) - defer os.RemoveAll(dir) + file := filepath.Join(t.TempDir(), "exist") + if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { + t.Fatal(err) + } beforeUnixEpochTime := unixEpochTime.Add(-100 * time.Second) afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) diff --git a/pkg/system/lstat_unix_test.go b/pkg/system/lstat_unix_test.go index 943b7d6c63..a38a524c4d 100644 --- a/pkg/system/lstat_unix_test.go +++ b/pkg/system/lstat_unix_test.go @@ -5,13 +5,17 @@ package system // import "github.com/docker/docker/pkg/system" import ( "os" + "path/filepath" "testing" ) // TestLstat tests Lstat for existing and non existing files func TestLstat(t *testing.T) { - file, invalid, _, dir := prepareFiles(t) - defer os.RemoveAll(dir) + tmpDir := t.TempDir() + file := filepath.Join(tmpDir, "exist") + if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { + t.Fatal(err) + } statFile, err := Lstat(file) if err != nil { @@ -21,7 +25,7 @@ func TestLstat(t *testing.T) { t.Fatal("returned empty stat for existing file") } - statInvalid, err := Lstat(invalid) + statInvalid, err := Lstat(filepath.Join(tmpDir, "nosuchfile")) if err == nil { t.Fatal("did not return error for non-existing file") } diff --git a/pkg/system/stat_unix_test.go b/pkg/system/stat_unix_test.go index 416b07eaa5..a7b6f3e22d 100644 --- a/pkg/system/stat_unix_test.go +++ b/pkg/system/stat_unix_test.go @@ -5,6 +5,7 @@ package system // import "github.com/docker/docker/pkg/system" import ( "os" + "path/filepath" "syscall" "testing" @@ -13,8 +14,10 @@ import ( // TestFromStatT tests fromStatT for a tempfile func TestFromStatT(t *testing.T) { - file, _, _, dir := prepareFiles(t) - defer os.RemoveAll(dir) + file := filepath.Join(t.TempDir(), "exist") + if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { + t.Fatal(err) + } stat := &syscall.Stat_t{} err := syscall.Lstat(file, stat) diff --git a/pkg/system/utimes_unix_test.go b/pkg/system/utimes_unix_test.go index 30482b7c07..fad50d5051 100644 --- a/pkg/system/utimes_unix_test.go +++ b/pkg/system/utimes_unix_test.go @@ -11,30 +11,26 @@ import ( ) // prepareFiles creates files for testing in the temp directory -func prepareFiles(t *testing.T) (string, string, string, string) { - dir, err := os.MkdirTemp("", "docker-system-test") - if err != nil { +func prepareFiles(t *testing.T) (file, invalid, symlink string) { + t.Helper() + dir := t.TempDir() + + file = filepath.Join(dir, "exist") + if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { t.Fatal(err) } - file := filepath.Join(dir, "exist") - if err := os.WriteFile(file, []byte("hello"), 0644); err != nil { - t.Fatal(err) - } - - invalid := filepath.Join(dir, "doesnt-exist") - - symlink := filepath.Join(dir, "symlink") + invalid = filepath.Join(dir, "doesnt-exist") + symlink = filepath.Join(dir, "symlink") if err := os.Symlink(file, symlink); err != nil { t.Fatal(err) } - return file, invalid, symlink, dir + return file, invalid, symlink } func TestLUtimesNano(t *testing.T) { - file, invalid, symlink, dir := prepareFiles(t) - defer os.RemoveAll(dir) + file, invalid, symlink := prepareFiles(t) before, err := os.Stat(file) if err != nil { From a9c5a40087348ac47d94f2cc71a8d76e946a1b98 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 7 Oct 2022 15:55:45 +0200 Subject: [PATCH 6/7] pkg/system: rename some tests to be more descriptive Removing the "Linux" suffix from one test, which should probably be rewritten to be run on "unix", to provide test-coverage for those implementations. Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes_linux_test.go | 4 ++-- pkg/system/chtimes_test.go | 5 +++-- pkg/system/chtimes_windows_test.go | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/system/chtimes_linux_test.go b/pkg/system/chtimes_linux_test.go index 4f3d7eac6d..091b8aba44 100644 --- a/pkg/system/chtimes_linux_test.go +++ b/pkg/system/chtimes_linux_test.go @@ -8,8 +8,8 @@ import ( "time" ) -// TestChtimesLinux tests Chtimes access time on a tempfile on Linux -func TestChtimesLinux(t *testing.T) { +// TestChtimesATime tests Chtimes access time on a tempfile. +func TestChtimesATime(t *testing.T) { file := filepath.Join(t.TempDir(), "exist") if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { t.Fatal(err) diff --git a/pkg/system/chtimes_test.go b/pkg/system/chtimes_test.go index 020c8806fb..eb85110a45 100644 --- a/pkg/system/chtimes_test.go +++ b/pkg/system/chtimes_test.go @@ -7,8 +7,9 @@ import ( "time" ) -// TestChtimes tests Chtimes on a tempfile. Test only mTime, because aTime is OS dependent -func TestChtimes(t *testing.T) { +// TestChtimesModTime tests Chtimes on a tempfile. Test only mTime, because +// aTime is OS dependent. +func TestChtimesModTime(t *testing.T) { file := filepath.Join(t.TempDir(), "exist") if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { t.Fatal(err) diff --git a/pkg/system/chtimes_windows_test.go b/pkg/system/chtimes_windows_test.go index 5c05e8e905..cd84f5643f 100644 --- a/pkg/system/chtimes_windows_test.go +++ b/pkg/system/chtimes_windows_test.go @@ -11,8 +11,8 @@ import ( "time" ) -// TestChtimesWindows tests Chtimes access time on a tempfile on Windows -func TestChtimesWindows(t *testing.T) { +// TestChtimesATimeWindows tests Chtimes access time on a tempfile on Windows. +func TestChtimesATimeWindows(t *testing.T) { file := filepath.Join(t.TempDir(), "exist") if err := os.WriteFile(file, []byte("hello"), 0o644); err != nil { t.Fatal(err) From a19ee75bd15140c73a3e5a91e25964a00a9f0559 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 7 Oct 2022 16:17:11 +0200 Subject: [PATCH 7/7] pkg/system: fix missing assertions and use sub-tests for ChTimes These tests were effectively doing "subtests", using comments to describe each, however; - due to the use of `t.Fatal()` would terminate before completing all "subtests" - The error returned by the function being tested (`Chtimes`), was not checked, and the test used "indirect" checks to verify if it worked correctly. Adding assertions to check if the function didn't produce an error. Signed-off-by: Sebastiaan van Stijn --- pkg/system/chtimes_linux_test.go | 120 +++++++++++++++++------------ pkg/system/chtimes_test.go | 100 ++++++++++++++---------- pkg/system/chtimes_windows_test.go | 110 +++++++++++++++----------- 3 files changed, 195 insertions(+), 135 deletions(-) diff --git a/pkg/system/chtimes_linux_test.go b/pkg/system/chtimes_linux_test.go index 091b8aba44..662aaf147d 100644 --- a/pkg/system/chtimes_linux_test.go +++ b/pkg/system/chtimes_linux_test.go @@ -19,72 +19,92 @@ func TestChtimesATime(t *testing.T) { afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) // Test both aTime and mTime set to Unix Epoch - Chtimes(file, unixEpochTime, unixEpochTime) + t.Run("both aTime and mTime set to Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, unixEpochTime, unixEpochTime); err != nil { + t.Error(err) + } - f, err := os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - stat := f.Sys().(*syscall.Stat_t) - aTime := time.Unix(stat.Atim.Unix()) - if aTime != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) - } + stat := f.Sys().(*syscall.Stat_t) + aTime := time.Unix(stat.Atim.Unix()) + if aTime != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) + } + }) // Test aTime before Unix Epoch and mTime set to Unix Epoch - Chtimes(file, beforeUnixEpochTime, unixEpochTime) + t.Run("aTime before Unix Epoch and mTime set to Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, beforeUnixEpochTime, unixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - stat = f.Sys().(*syscall.Stat_t) - aTime = time.Unix(stat.Atim.Unix()) - if aTime != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) - } + stat := f.Sys().(*syscall.Stat_t) + aTime := time.Unix(stat.Atim.Unix()) + if aTime != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) + } + }) // Test aTime set to Unix Epoch and mTime before Unix Epoch - Chtimes(file, unixEpochTime, beforeUnixEpochTime) + t.Run("aTime set to Unix Epoch and mTime before Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, unixEpochTime, beforeUnixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - stat = f.Sys().(*syscall.Stat_t) - aTime = time.Unix(stat.Atim.Unix()) - if aTime != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) - } + stat := f.Sys().(*syscall.Stat_t) + aTime := time.Unix(stat.Atim.Unix()) + if aTime != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) + } + }) // Test both aTime and mTime set to after Unix Epoch (valid time) - Chtimes(file, afterUnixEpochTime, afterUnixEpochTime) + t.Run("both aTime and mTime set to after Unix Epoch (valid time)", func(t *testing.T) { + if err := Chtimes(file, afterUnixEpochTime, afterUnixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - stat = f.Sys().(*syscall.Stat_t) - aTime = time.Unix(stat.Atim.Unix()) - if aTime != afterUnixEpochTime { - t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime) - } + stat := f.Sys().(*syscall.Stat_t) + aTime := time.Unix(stat.Atim.Unix()) + if aTime != afterUnixEpochTime { + t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime) + } + }) // Test both aTime and mTime set to Unix max time - Chtimes(file, unixMaxTime, unixMaxTime) + t.Run("both aTime and mTime set to Unix max time", func(t *testing.T) { + if err := Chtimes(file, unixMaxTime, unixMaxTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - stat = f.Sys().(*syscall.Stat_t) - aTime = time.Unix(stat.Atim.Unix()) - if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) { - t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second)) - } + stat := f.Sys().(*syscall.Stat_t) + aTime := time.Unix(stat.Atim.Unix()) + if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) { + t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second)) + } + }) } diff --git a/pkg/system/chtimes_test.go b/pkg/system/chtimes_test.go index eb85110a45..ad95df2f09 100644 --- a/pkg/system/chtimes_test.go +++ b/pkg/system/chtimes_test.go @@ -19,62 +19,82 @@ func TestChtimesModTime(t *testing.T) { afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) // Test both aTime and mTime set to Unix Epoch - Chtimes(file, unixEpochTime, unixEpochTime) + t.Run("both aTime and mTime set to Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, unixEpochTime, unixEpochTime); err != nil { + t.Error(err) + } - f, err := os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - if f.ModTime() != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime()) - } + if f.ModTime() != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime()) + } + }) // Test aTime before Unix Epoch and mTime set to Unix Epoch - Chtimes(file, beforeUnixEpochTime, unixEpochTime) + t.Run("aTime before Unix Epoch and mTime set to Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, beforeUnixEpochTime, unixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - if f.ModTime() != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime()) - } + if f.ModTime() != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime()) + } + }) // Test aTime set to Unix Epoch and mTime before Unix Epoch - Chtimes(file, unixEpochTime, beforeUnixEpochTime) + t.Run("aTime set to Unix Epoch and mTime before Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, unixEpochTime, beforeUnixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - if f.ModTime() != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime()) - } + if f.ModTime() != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime()) + } + }) // Test both aTime and mTime set to after Unix Epoch (valid time) - Chtimes(file, afterUnixEpochTime, afterUnixEpochTime) + t.Run("both aTime and mTime set to after Unix Epoch (valid time)", func(t *testing.T) { + if err := Chtimes(file, afterUnixEpochTime, afterUnixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - if f.ModTime() != afterUnixEpochTime { - t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, f.ModTime()) - } + if f.ModTime() != afterUnixEpochTime { + t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, f.ModTime()) + } + }) // Test both aTime and mTime set to Unix max time - Chtimes(file, unixMaxTime, unixMaxTime) + t.Run("both aTime and mTime set to Unix max time", func(t *testing.T) { + if err := Chtimes(file, unixMaxTime, unixMaxTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - if f.ModTime().Truncate(time.Second) != unixMaxTime.Truncate(time.Second) { - t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), f.ModTime().Truncate(time.Second)) - } + if f.ModTime().Truncate(time.Second) != unixMaxTime.Truncate(time.Second) { + t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), f.ModTime().Truncate(time.Second)) + } + }) } diff --git a/pkg/system/chtimes_windows_test.go b/pkg/system/chtimes_windows_test.go index cd84f5643f..6184336f3e 100644 --- a/pkg/system/chtimes_windows_test.go +++ b/pkg/system/chtimes_windows_test.go @@ -22,67 +22,87 @@ func TestChtimesATimeWindows(t *testing.T) { afterUnixEpochTime := unixEpochTime.Add(100 * time.Second) // Test both aTime and mTime set to Unix Epoch - Chtimes(file, unixEpochTime, unixEpochTime) + t.Run("both aTime and mTime set to Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, unixEpochTime, unixEpochTime); err != nil { + t.Error(err) + } - f, err := os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) - if aTime != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) - } + aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) + if aTime != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) + } + }) // Test aTime before Unix Epoch and mTime set to Unix Epoch - Chtimes(file, beforeUnixEpochTime, unixEpochTime) + t.Run("aTime before Unix Epoch and mTime set to Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, beforeUnixEpochTime, unixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) - if aTime != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) - } + aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) + if aTime != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) + } + }) // Test aTime set to Unix Epoch and mTime before Unix Epoch - Chtimes(file, unixEpochTime, beforeUnixEpochTime) + t.Run("aTime set to Unix Epoch and mTime before Unix Epoch", func(t *testing.T) { + if err := Chtimes(file, unixEpochTime, beforeUnixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) - if aTime != unixEpochTime { - t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) - } + aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) + if aTime != unixEpochTime { + t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime) + } + }) // Test both aTime and mTime set to after Unix Epoch (valid time) - Chtimes(file, afterUnixEpochTime, afterUnixEpochTime) + t.Run("both aTime and mTime set to after Unix Epoch (valid time)", func(t *testing.T) { + if err := Chtimes(file, afterUnixEpochTime, afterUnixEpochTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) - if aTime != afterUnixEpochTime { - t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime) - } + aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) + if aTime != afterUnixEpochTime { + t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime) + } + }) // Test both aTime and mTime set to Unix max time - Chtimes(file, unixMaxTime, unixMaxTime) + t.Run("both aTime and mTime set to Unix max time", func(t *testing.T) { + if err := Chtimes(file, unixMaxTime, unixMaxTime); err != nil { + t.Error(err) + } - f, err = os.Stat(file) - if err != nil { - t.Fatal(err) - } + f, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } - aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) - if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) { - t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second)) - } + aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) + if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) { + t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second)) + } + }) }