]> Cypherpunks repositories - gostls13.git/commitdiff
os: relax tests and add examples for UserCacheDir and UserConfigDir
authorBryan C. Mills <bcmills@google.com>
Mon, 8 Jan 2024 22:20:14 +0000 (17:20 -0500)
committerGopher Robot <gobot@golang.org>
Wed, 10 Jan 2024 17:35:49 +0000 (17:35 +0000)
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 <austin@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Bryan Mills <bcmills@google.com>

src/os/example_test.go
src/os/os_test.go

index 656232c472e0a465475cc33f494df587b0301354..7437a74cd0c66d657dd6b52e7646abf92c18bf9a 100644 (file)
@@ -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:
+}
index 2f5b117bd90ff57aa9a4add054e5a8a2cb87f87d..6adc3b547924be385752a6cf0a93dd7a07a43784 100644 (file)
@@ -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) {