From: Bryan C. Mills Date: Mon, 8 Jan 2024 22:20:14 +0000 (-0500) Subject: os: relax tests and add examples for UserCacheDir and UserConfigDir X-Git-Tag: go1.22rc2~7^2~20 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e9b3ff15f40d6b258217b3467c662f816b078477;p=gostls13.git os: relax tests and add examples for UserCacheDir and UserConfigDir Per https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html: “If, when attempting to write a file, the destination directory is non-existent an attempt should be made to create it with permission 0700. […] The application should be prepared to handle the case where the file could not be written […]. In such case it may choose to present an error message to the user.” In certain CI environments, these directories have well-defined locations but do not exist and cannot be created. In that case, we now choose to log and return from the test without failing it. To prevent the functions from falling back to being entirely untested, we still fail the test (and “present an error message to the user”) if either function returns an empty string without an error, or returns a path that refers to a non-directory or results in an error other than ErrNotExist. In addition, since the tests themselves no longer create subdirectories, we add examples illustrating the suggested pattern of usage. Fixes #64990. Change-Id: Ie72106424f5ebe36eaf9288c22710d74bb14a462 Reviewed-on: https://go-review.googlesource.com/c/go/+/554815 Reviewed-by: Austin Clements Run-TryBot: Bryan Mills LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot Auto-Submit: Bryan Mills --- diff --git a/src/os/example_test.go b/src/os/example_test.go index 656232c472..7437a74cd0 100644 --- a/src/os/example_test.go +++ b/src/os/example_test.go @@ -5,12 +5,14 @@ package os_test import ( + "bytes" "errors" "fmt" "io/fs" "log" "os" "path/filepath" + "sync" "time" ) @@ -317,3 +319,77 @@ func ExampleReadlink() { // Output: // hello.link links to hello.txt } + +func ExampleUserCacheDir() { + dir, dirErr := os.UserCacheDir() + if dirErr == nil { + dir = filepath.Join(dir, "ExampleUserCacheDir") + } + + getCache := func(name string) ([]byte, error) { + if dirErr != nil { + return nil, &os.PathError{Op: "getCache", Path: name, Err: os.ErrNotExist} + } + return os.ReadFile(filepath.Join(dir, name)) + } + + var mkdirOnce sync.Once + putCache := func(name string, b []byte) error { + if dirErr != nil { + return &os.PathError{Op: "putCache", Path: name, Err: dirErr} + } + mkdirOnce.Do(func() { + if err := os.MkdirAll(dir, 0700); err != nil { + log.Printf("can't create user cache dir: %v", err) + } + }) + return os.WriteFile(filepath.Join(dir, name), b, 0600) + } + + // Read and store cached data. + // … + _ = getCache + _ = putCache + + // Output: +} + +func ExampleUserConfigDir() { + dir, dirErr := os.UserConfigDir() + + var ( + configPath string + origConfig []byte + ) + if dirErr == nil { + configPath = filepath.Join(dir, "ExampleUserConfigDir", "example.conf") + var err error + origConfig, err = os.ReadFile(configPath) + if err != nil && !os.IsNotExist(err) { + // The user has a config file but we couldn't read it. + // Report the error instead of ignoring their configuration. + log.Fatal(err) + } + } + + // Use and perhaps make changes to the config. + config := bytes.Clone(origConfig) + // … + + // Save changes. + if !bytes.Equal(config, origConfig) { + if configPath == "" { + log.Printf("not saving config changes: %v", dirErr) + } else { + err := os.MkdirAll(filepath.Dir(configPath), 0700) + if err == nil { + err = os.WriteFile(configPath, config, 0600) + } + if err != nil { + log.Printf("error saving config changes: %v", err) + } + } + } + + // Output: +} diff --git a/src/os/os_test.go b/src/os/os_test.go index 2f5b117bd9..6adc3b5479 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -11,6 +11,7 @@ import ( "internal/testenv" "io" "io/fs" + "log" . "os" "os/exec" "path/filepath" @@ -33,6 +34,8 @@ func TestMain(m *testing.M) { Exit(0) } + log.SetFlags(log.LstdFlags | log.Lshortfile) + Exit(m.Run()) } @@ -2847,16 +2850,17 @@ func TestUserCacheDir(t *testing.T) { t.Fatalf("UserCacheDir returned %q; want non-empty path or error", dir) } - if err := MkdirAll(dir, 0777); err != nil { - t.Fatalf("could not create UserCacheDir: %v", err) - } - d, err := MkdirTemp(dir, "TestUserCacheDir") + fi, err := Stat(dir) if err != nil { - t.Fatalf("could not create a directory in UserCacheDir: %v", err) - } - if err := Remove(d); err != nil { + if IsNotExist(err) { + t.Log(err) + return + } t.Fatal(err) } + if !fi.IsDir() { + t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode()) + } } func TestUserConfigDir(t *testing.T) { @@ -2870,17 +2874,17 @@ func TestUserConfigDir(t *testing.T) { t.Fatalf("UserConfigDir returned %q; want non-empty path or error", dir) } - if err := MkdirAll(dir, 0777); err != nil { - t.Fatalf("could not create UserConfigDir: %v", err) - } - - d, err := MkdirTemp(dir, "TestUserConfigDir") + fi, err := Stat(dir) if err != nil { - t.Fatalf("could not create a directory in UserConfigDir: %v", err) - } - if err := Remove(d); err != nil { + if IsNotExist(err) { + t.Log(err) + return + } t.Fatal(err) } + if !fi.IsDir() { + t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode()) + } } func TestUserHomeDir(t *testing.T) {