1
0
Fork 0
mirror of https://github.com/vbatts/go-mtree.git synced 2025-10-03 20:21:01 +00:00
go-mtree/check_test.go
Aleksa Sarai 3252a4ad82
test: migrate most tests to testify
testify makes most bog-standard test checks much easier to read and
maintain, and is quite widely used. It wasn't really well known back
when go-mtree was first written, but the migration is fairly
straight-forward for most tests.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2025-09-20 12:43:45 +10:00

245 lines
7 KiB
Go

package mtree
import (
"bytes"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// simple walk of current directory, and immediately check it.
// may not be parallelizable.
func TestCheck(t *testing.T) {
dh, err := Walk(".", nil, append(DefaultKeywords, []Keyword{"sha1", "xattr"}...), nil)
require.NoError(t, err, "walk .")
res, err := Check(".", dh, nil, nil)
require.NoError(t, err, "check .")
if !assert.Empty(t, res, "check after no changes should have no diff") {
pprintInodeDeltas(t, res)
}
}
// make a directory, walk it, check it, modify the timestamp and ensure it fails.
// only check again for size and sha1, and ignore time, and ensure it passes
func TestCheckKeywords(t *testing.T) {
content := []byte("I know half of you half as well as I ought to")
dir := t.TempDir()
tmpfn := filepath.Join(dir, "tmpfile")
require.NoError(t, os.WriteFile(tmpfn, content, 0666))
// Walk this tempdir
dh, err := Walk(dir, nil, append(DefaultKeywords, "sha1"), nil)
require.NoErrorf(t, err, "walk %s", dir)
// Check for sanity. This ought to pass.
res, err := Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s", dir)
if !assert.Empty(t, res, "check after no changes should have no diff") {
pprintInodeDeltas(t, res)
}
// Touch a file, so the mtime changes.
newtime := time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC)
require.NoError(t, os.Chtimes(tmpfn, newtime, newtime))
// Check again. This ought to fail.
res, err = Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s", dir)
if assert.NotEmpty(t, res, "should get a delta after mtime change") {
assert.Len(t, res, 1, "should only be one changed file entry")
diff := res[0]
assert.Equal(t, Modified, diff.Type(), "expected to get modified entry")
kds := diff.Diff()
if assert.Len(t, kds, 1, "should have one key different after mtime change") {
kd := kds[0]
assert.Equal(t, Modified, kd.Type(), "after mtime change key delta type should be modified")
assert.Equal(t, Keyword("time"), kd.Name(), "after mtime change key delta should be 'time'")
assert.NotNil(t, kd.Old(), "after mtime change key delta Old")
assert.NotNil(t, kd.New(), "after mtime change key delta New")
}
}
// Check again, but only sha1 and mode. This ought to pass.
res, err = Check(dir, dh, []Keyword{"sha1", "mode"}, nil)
require.NoErrorf(t, err, "check .", err)
if !assert.Empty(t, res, "check (~time) should have no diff") {
pprintInodeDeltas(t, res)
}
}
func ExampleCheck() {
dh, err := Walk(".", nil, append(DefaultKeywords, "sha1"), nil)
if err != nil {
// handle error ...
}
res, err := Check(".", dh, nil, nil)
if err != nil {
// handle error ...
}
if len(res) > 0 {
// handle failed validity ...
}
}
// Tests default action for evaluating a symlink, which is just to compare the
// link itself, not to follow it
func TestDefaultBrokenLink(t *testing.T) {
dir := "./testdata/dirwithbrokenlink"
dh, err := Walk(dir, nil, append(DefaultKeywords, "sha1"), nil)
require.NoErrorf(t, err, "walk %s", dir)
res, err := Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s", dir)
if !assert.Empty(t, res, "check after no changes should have no diff") {
pprintInodeDeltas(t, res)
}
}
// https://github.com/vbatts/go-mtree/issues/8
func TestTimeComparison(t *testing.T) {
dir := t.TempDir()
// This is the format of time from FreeBSD
spec := `
/set type=file time=5.000000000
. type=dir
file time=5.000000000
..
`
fh, err := os.Create(filepath.Join(dir, "file"))
require.NoError(t, err)
// This is what mode we're checking for. Round integer of epoch seconds
epoch := time.Unix(5, 0)
require.NoError(t, os.Chtimes(fh.Name(), epoch, epoch))
require.NoError(t, os.Chtimes(dir, epoch, epoch))
require.NoError(t, fh.Close())
dh, err := ParseSpec(bytes.NewBufferString(spec))
require.NoError(t, err, "parse specfile")
res, err := Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s against spec", dir)
if !assert.Empty(t, res) {
pprintInodeDeltas(t, res)
}
}
func TestTarTime(t *testing.T) {
dir := t.TempDir()
// This is the format of time from FreeBSD
spec := `
/set type=file time=5.454353132
. type=dir time=5.123456789
file time=5.911134111
..
`
fh, err := os.Create(filepath.Join(dir, "file"))
require.NoError(t, err)
// This is what mode we're checking for. Round integer of epoch seconds
epoch := time.Unix(5, 0)
require.NoError(t, os.Chtimes(fh.Name(), epoch, epoch))
require.NoError(t, os.Chtimes(dir, epoch, epoch))
require.NoError(t, fh.Close())
dh, err := ParseSpec(bytes.NewBufferString(spec))
require.NoError(t, err, "parse specfile")
keywords := dh.UsedKeywords()
assert.ElementsMatch(t, keywords, []Keyword{"type", "time"}, "UsedKeywords")
// make sure "time" keyword works
res1, err := Check(dir, dh, keywords, nil)
require.NoErrorf(t, err, "check %s (UsedKeywords)", dir)
assert.NotEmpty(t, res1, "check should have errors when time mismatched")
// make sure tar_time wins
res2, err := Check(dir, dh, append(keywords, "tar_time"), nil)
require.NoErrorf(t, err, "check %s (UsedKeywords + tar_time)", dir)
if !assert.Empty(t, res2, "tar_time should check against truncated timestamp") {
pprintInodeDeltas(t, res2)
}
}
func TestIgnoreComments(t *testing.T) {
dir := t.TempDir()
// This is the format of time from FreeBSD
spec := `
/set type=file time=5.000000000
. type=dir
file1 time=5.000000000
..
`
fh, err := os.Create(filepath.Join(dir, "file1"))
require.NoError(t, err)
// This is what mode we're checking for. Round integer of epoch seconds
epoch := time.Unix(5, 0)
require.NoError(t, os.Chtimes(fh.Name(), epoch, epoch))
require.NoError(t, os.Chtimes(dir, epoch, epoch))
require.NoError(t, fh.Close())
dh, err := ParseSpec(bytes.NewBufferString(spec))
require.NoError(t, err, "parse specfile")
res, err := Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s", dir)
if !assert.Empty(t, res) {
pprintInodeDeltas(t, res)
}
// now change the spec to a comment that looks like an actual Entry but has
// whitespace in front of it
spec = `
/set type=file time=5.000000000
. type=dir
file1 time=5.000000000
#file2 time=5.000000000
..
`
dh, err = ParseSpec(bytes.NewBufferString(spec))
require.NoError(t, err, "parse specfile")
res, err = Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s", dir)
if !assert.Empty(t, res) {
pprintInodeDeltas(t, res)
}
}
func TestCheckNeedsEncoding(t *testing.T) {
dir := t.TempDir()
fh, err := os.Create(filepath.Join(dir, "file[ "))
require.NoError(t, err)
require.NoError(t, fh.Close())
fh, err = os.Create(filepath.Join(dir, " , should work"))
require.NoError(t, err)
require.NoError(t, fh.Close())
dh, err := Walk(dir, nil, DefaultKeywords, nil)
require.NoErrorf(t, err, "walk %s", dir)
res, err := Check(dir, dh, nil, nil)
require.NoErrorf(t, err, "check %s", dir)
if !assert.Empty(t, res) {
pprintInodeDeltas(t, res)
}
}