restic/internal/fuse/snapshots_dirstruct_test.go

292 lines
10 KiB
Go

//go:build darwin || freebsd || linux
// +build darwin freebsd linux
package fuse
import (
"strings"
"testing"
"time"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/test"
)
func TestPathsFromSn(t *testing.T) {
id1, _ := restic.ParseID("1234567812345678123456781234567812345678123456781234567812345678")
time1, _ := time.Parse("2006-01-02T15:04:05", "2021-01-01T00:00:01")
sn1 := &restic.Snapshot{Hostname: "host", Username: "user", Tags: []string{"tag1", "tag2"}, Time: time1}
restic.TestSetSnapshotID(t, sn1, id1)
var p []string
var s string
p, s = pathsFromSn("ids/%i", "2006-01-02T15:04:05", sn1)
test.Equals(t, []string{"ids/12345678"}, p)
test.Equals(t, "", s)
p, s = pathsFromSn("snapshots/%T", "2006-01-02T15:04:05", sn1)
test.Equals(t, []string{"snapshots/"}, p)
test.Equals(t, "2021-01-01T00:00:01", s)
p, s = pathsFromSn("hosts/%h/%T", "2006-01-02T15:04:05", sn1)
test.Equals(t, []string{"hosts/host/"}, p)
test.Equals(t, "2021-01-01T00:00:01", s)
p, s = pathsFromSn("tags/%t/%T", "2006-01-02T15:04:05", sn1)
test.Equals(t, []string{"tags/tag1/", "tags/tag2/"}, p)
test.Equals(t, "2021-01-01T00:00:01", s)
p, s = pathsFromSn("users/%u/%T", "2006-01-02T15:04:05", sn1)
test.Equals(t, []string{"users/user/"}, p)
test.Equals(t, "2021-01-01T00:00:01", s)
p, s = pathsFromSn("longids/%I", "2006-01-02T15:04:05", sn1)
test.Equals(t, []string{"longids/1234567812345678123456781234567812345678123456781234567812345678"}, p)
test.Equals(t, "", s)
p, s = pathsFromSn("%T/%h", "2006/01/02", sn1)
test.Equals(t, []string{"2021/01/01/host"}, p)
test.Equals(t, "", s)
p, s = pathsFromSn("%T/%i", "2006/01", sn1)
test.Equals(t, []string{"2021/01/12345678"}, p)
test.Equals(t, "", s)
}
func TestMakeDirs(t *testing.T) {
pathTemplates := []string{"ids/%i", "snapshots/%T", "hosts/%h/%T",
"tags/%t/%T", "users/%u/%T", "longids/%I", "%T/%h", "%T/%i",
}
timeTemplate := "2006/01/02"
sds := &SnapshotsDirStructure{
pathTemplates: pathTemplates,
timeTemplate: timeTemplate,
}
id0, _ := restic.ParseID("0000000012345678123456781234567812345678123456781234567812345678")
time0, _ := time.Parse("2006-01-02T15:04:05", "2020-12-31T00:00:01")
sn0 := &restic.Snapshot{Hostname: "host", Username: "user", Tags: []string{"tag1", "tag2"}, Time: time0}
restic.TestSetSnapshotID(t, sn0, id0)
id1, _ := restic.ParseID("1234567812345678123456781234567812345678123456781234567812345678")
time1, _ := time.Parse("2006-01-02T15:04:05", "2021-01-01T00:00:01")
sn1 := &restic.Snapshot{Hostname: "host", Username: "user", Tags: []string{"tag1", "tag2"}, Time: time1}
restic.TestSetSnapshotID(t, sn1, id1)
id2, _ := restic.ParseID("8765432112345678123456781234567812345678123456781234567812345678")
time2, _ := time.Parse("2006-01-02T15:04:05", "2021-01-01T01:02:03")
sn2 := &restic.Snapshot{Hostname: "host2", Username: "user2", Tags: []string{"tag2", "tag3", "tag4"}, Time: time2}
restic.TestSetSnapshotID(t, sn2, id2)
id3, _ := restic.ParseID("aaaaaaaa12345678123456781234567812345678123456781234567812345678")
time3, _ := time.Parse("2006-01-02T15:04:05", "2021-01-01T01:02:03")
sn3 := &restic.Snapshot{Hostname: "host", Username: "user2", Tags: []string{}, Time: time3}
restic.TestSetSnapshotID(t, sn3, id3)
sds.makeDirs(restic.Snapshots{sn0, sn1, sn2, sn3})
expNames := make(map[string]*restic.Snapshot)
expLatest := make(map[string]string)
// entries for sn0
expNames["/ids/00000000"] = sn0
expNames["/snapshots/2020/12/31"] = sn0
expNames["/hosts/host/2020/12/31"] = sn0
expNames["/tags/tag1/2020/12/31"] = sn0
expNames["/tags/tag2/2020/12/31"] = sn0
expNames["/users/user/2020/12/31"] = sn0
expNames["/longids/0000000012345678123456781234567812345678123456781234567812345678"] = sn0
expNames["/2020/12/31/host"] = sn0
expNames["/2020/12/31/00000000"] = sn0
// entries for sn1
expNames["/ids/12345678"] = sn1
expNames["/snapshots/2021/01/01"] = sn1
expNames["/hosts/host/2021/01/01"] = sn1
expNames["/tags/tag1/2021/01/01"] = sn1
expNames["/tags/tag2/2021/01/01"] = sn1
expNames["/users/user/2021/01/01"] = sn1
expNames["/longids/1234567812345678123456781234567812345678123456781234567812345678"] = sn1
expNames["/2021/01/01/host"] = sn1
expNames["/2021/01/01/12345678"] = sn1
// entries for sn2
expNames["/ids/87654321"] = sn2
expNames["/snapshots/2021/01/01-1"] = sn2 // sn1 and sn2 have same time string
expNames["/hosts/host2/2021/01/01"] = sn2
expNames["/tags/tag2/2021/01/01-1"] = sn2 // sn1 and sn2 have same time string
expNames["/tags/tag3/2021/01/01"] = sn2
expNames["/tags/tag4/2021/01/01"] = sn2
expNames["/users/user2/2021/01/01"] = sn2
expNames["/longids/8765432112345678123456781234567812345678123456781234567812345678"] = sn2
expNames["/2021/01/01/host2"] = sn2
expNames["/2021/01/01/87654321"] = sn2
// entries for sn3
expNames["/ids/aaaaaaaa"] = sn3
expNames["/snapshots/2021/01/01-2"] = sn3 // sn1 - sn3 have same time string
expNames["/hosts/host/2021/01/01-1"] = sn3 // sn1 and sn3 have same time string
expNames["/users/user2/2021/01/01-1"] = sn3 // sn2 and sn3 have same time string
expNames["/longids/aaaaaaaa12345678123456781234567812345678123456781234567812345678"] = sn3
expNames["/2021/01/01/host-1"] = sn3 // sn1 and sn3 have same time string and identical host
expNames["/2021/01/01/aaaaaaaa"] = sn3
// intermediate directories
// sn0
expNames["/ids"] = nil
expNames[""] = nil
expNames["/snapshots/2020/12"] = nil
expNames["/snapshots/2020"] = nil
expNames["/snapshots"] = nil
expNames["/hosts/host/2020/12"] = nil
expNames["/hosts/host/2020"] = nil
expNames["/hosts/host"] = nil
expNames["/hosts"] = nil
expNames["/tags/tag1/2020/12"] = nil
expNames["/tags/tag1/2020"] = nil
expNames["/tags/tag1"] = nil
expNames["/tags"] = nil
expNames["/tags/tag2/2020/12"] = nil
expNames["/tags/tag2/2020"] = nil
expNames["/tags/tag2"] = nil
expNames["/users/user/2020/12"] = nil
expNames["/users/user/2020"] = nil
expNames["/users/user"] = nil
expNames["/users"] = nil
expNames["/longids"] = nil
expNames["/2020/12/31"] = nil
expNames["/2020/12"] = nil
expNames["/2020"] = nil
// sn1
expNames["/snapshots/2021/01"] = nil
expNames["/snapshots/2021"] = nil
expNames["/hosts/host/2021/01"] = nil
expNames["/hosts/host/2021"] = nil
expNames["/tags/tag1/2021/01"] = nil
expNames["/tags/tag1/2021"] = nil
expNames["/tags/tag2/2021/01"] = nil
expNames["/tags/tag2/2021"] = nil
expNames["/users/user/2021/01"] = nil
expNames["/users/user/2021"] = nil
expNames["/2021/01/01"] = nil
expNames["/2021/01"] = nil
expNames["/2021"] = nil
// sn2
expNames["/hosts/host2/2021/01"] = nil
expNames["/hosts/host2/2021"] = nil
expNames["/hosts/host2"] = nil
expNames["/tags/tag3/2021/01"] = nil
expNames["/tags/tag3/2021"] = nil
expNames["/tags/tag3"] = nil
expNames["/tags/tag4/2021/01"] = nil
expNames["/tags/tag4/2021"] = nil
expNames["/tags/tag4"] = nil
expNames["/users/user2/2021/01"] = nil
expNames["/users/user2/2021"] = nil
expNames["/users/user2"] = nil
// target snapshots for links
expNames["/snapshots/latest"] = sn3 // sn1 - sn3 have same time string
expNames["/hosts/host/latest"] = sn3
expNames["/hosts/host2/latest"] = sn2
expNames["/tags/tag1/latest"] = sn1
expNames["/tags/tag2/latest"] = sn2 // sn1 and sn2 have same time string
expNames["/tags/tag3/latest"] = sn2
expNames["/tags/tag4/latest"] = sn2
expNames["/users/user/latest"] = sn1
expNames["/users/user2/latest"] = sn3 // sn2 and sn3 have same time string
// latest links
expLatest["/snapshots/latest"] = "2021/01/01-2" // sn1 - sn3 have same time string
expLatest["/hosts/host/latest"] = "2021/01/01-1"
expLatest["/hosts/host2/latest"] = "2021/01/01"
expLatest["/tags/tag1/latest"] = "2021/01/01"
expLatest["/tags/tag2/latest"] = "2021/01/01-1" // sn1 and sn2 have same time string
expLatest["/tags/tag3/latest"] = "2021/01/01"
expLatest["/tags/tag4/latest"] = "2021/01/01"
expLatest["/users/user/latest"] = "2021/01/01"
expLatest["/users/user2/latest"] = "2021/01/01-1" // sn2 and sn3 have same time string
verifyEntries(t, expNames, expLatest, sds.entries)
}
func verifyEntries(t *testing.T, expNames map[string]*restic.Snapshot, expLatest map[string]string, entries map[string]*MetaDirData) {
actNames := make(map[string]*restic.Snapshot)
actLatest := make(map[string]string)
for path, entry := range entries {
actNames[path] = entry.snapshot
if entry.linkTarget != "" {
actLatest[path] = entry.linkTarget
}
}
test.Equals(t, expNames, actNames)
test.Equals(t, expLatest, actLatest)
// verify tree integrity
for path, entry := range entries {
// check that all children are actually contained in entry.names
for otherPath := range entries {
if strings.HasPrefix(otherPath, path+"/") {
sub := otherPath[len(path)+1:]
// remaining path does not contain a directory
test.Assert(t, strings.Contains(sub, "/") || (entry.names != nil && entry.names[sub] != nil), "missing entry %v in %v", sub, path)
}
}
if entry.names == nil {
continue
}
// child entries reference the correct MetaDirData
for elem, subentry := range entry.names {
test.Equals(t, entries[path+"/"+elem], subentry)
}
}
}
func TestMakeEmptyDirs(t *testing.T) {
pathTemplates := []string{"ids/%i", "snapshots/%T", "hosts/%h/%T",
"tags/%t/%T", "users/%u/%T", "longids/id-%I", "%T/%h", "%T/%i", "id-%i",
}
timeTemplate := "2006/01/02"
sds := &SnapshotsDirStructure{
pathTemplates: pathTemplates,
timeTemplate: timeTemplate,
}
sds.makeDirs(restic.Snapshots{})
expNames := make(map[string]*restic.Snapshot)
expLatest := make(map[string]string)
// empty entries for dir structure
expNames["/ids"] = nil
expNames["/snapshots"] = nil
expNames["/hosts"] = nil
expNames["/tags"] = nil
expNames["/users"] = nil
expNames["/longids"] = nil
expNames[""] = nil
verifyEntries(t, expNames, expLatest, sds.entries)
}
func TestFilenameFromTag(t *testing.T) {
for _, c := range []struct {
tag, filename string
}{
{"", "_"},
{".", "_"},
{"..", "__"},
{"%.", "%."},
{"foo", "foo"},
{"foo ", "foo "},
{"foo/bar_baz", "foo_bar_baz"},
} {
test.Equals(t, c.filename, filenameFromTag(c.tag))
}
}