author | Alberto Bertogli
<albertito@blitiri.com.ar> 2023-08-30 00:03:03 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2023-08-30 00:03:03 UTC |
parent | 67bb7eb32c9c403aed863740a4d8f18ad9100d11 |
errors_test.go | +124 | -0 |
test/cover.sh | +2 | -0 |
diff --git a/errors_test.go b/errors_test.go new file mode 100644 index 0000000..3c9cd8a --- /dev/null +++ b/errors_test.go @@ -0,0 +1,124 @@ +package main + +import ( + "errors" + "io/fs" + "os" + "syscall" + "testing" +) + +// Tests for errors that are not feasible to cover by the end to end tests. +// For example, db.Read() calls are usually preceded by a db.Has(), so we +// can't easily simulate Read seeing an "xattr not found" in an end-to-end +// test. + +func TestDBReadError(t *testing.T) { + f, err := os.Open("/dev/null") + if err != nil { + t.Fatal(err) + } + defer f.Close() + + db := XattrDB{} + _, err = db.Read(f) + + if !errors.Is(err, syscall.ENODATA) { + t.Fatalf("expected ENODATA, got %v", err) + } +} + +var testErr = errors.New("test error") + +type fakeDirEntry struct{} + +func (f fakeDirEntry) Name() string { + return "fake" +} + +func (f fakeDirEntry) IsDir() bool { + return false +} + +func (f fakeDirEntry) Type() fs.FileMode { + return fs.FileMode(0777) +} + +func (f fakeDirEntry) Info() (os.FileInfo, error) { + return nil, testErr +} + +func TestOpenAndInfoError(t *testing.T) { + ok, _, _, err := openAndInfo("fake", fakeDirEntry{}, nil, 0) + if !ok || err != testErr { + t.Fatalf("expected ok, testErr, got %v, %v", ok, err) + } +} + +type fakeDB struct { + hasAttr bool + hasErr error + + readChecksum ChecksumV1 + readErr error + + writeErr error +} + +func (db fakeDB) Has(f *os.File) (bool, error) { + return db.hasAttr, db.hasErr +} + +func (db fakeDB) Read(f *os.File) (ChecksumV1, error) { + return db.readChecksum, db.readErr +} + +func (db fakeDB) Write(f *os.File, c ChecksumV1) error { + return db.writeErr +} + +func (db fakeDB) Close() error { + return nil +} + +func TestWalkingFunctionsHandleDBErrors(t *testing.T) { + // Test how the various walking functions (generate, update, verify) + // handle errors from the database. + cases := []struct { + fn walkFn + db fakeDB + expected error + }{ + {generate, fakeDB{}, nil}, + {generate, fakeDB{hasErr: testErr}, testErr}, + {generate, fakeDB{writeErr: testErr}, testErr}, + + {verify, fakeDB{}, nil}, + {verify, fakeDB{hasErr: testErr}, testErr}, + + {update, fakeDB{}, nil}, + {update, fakeDB{hasAttr: true}, nil}, + {update, fakeDB{hasErr: testErr}, testErr}, + {update, fakeDB{hasAttr: true, readErr: testErr}, testErr}, + } + + p := NewProgress(false) + + for _, c := range cases { + f, err := os.Open("/dev/null") + if err != nil { + t.Fatal(err) + } + info, err := f.Stat() + if err != nil { + t.Fatal(err) + } + + options.db = c.db + + err = c.fn(f, info, p) + if err != c.expected { + t.Fatalf("expected %v, got %v", c.expected, err) + } + } +} diff --git a/test/cover.sh b/test/cover.sh index 90dd6b4..259cf2a 100755 --- a/test/cover.sh +++ b/test/cover.sh @@ -12,6 +12,8 @@ export BUILDARGS="-cover" # Coverage tests require Go >= 1.20. go version +go test -cover ../... -args -test.gocoverdir="${GOCOVERDIR?}" + ./test.sh go tool covdata percent -i="${GOCOVERDIR?}"