blob: 7acc4db6e8486642819aed11dbd3629865c6116b [file] [log] [blame]
// Copyright 2017 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package test
import (
"crypto/rand"
"fmt"
"testing"
"time"
"upspin.io/errors"
"upspin.io/path"
"upspin.io/test/testenv"
"upspin.io/upspin"
)
func testSnapshot(t *testing.T, r *testenv.Runner) {
const (
base = ownerName + "/snapshot-test"
dir = base + "/dir"
file = dir + "/file"
accessFile = base + "/Access"
access = "*:all" // intentionally permissive.
snapshotDir = snapshotUser + "/"
// must be in sync with dir/server/snapshot.go
snapshotControlFile = snapshotDir + "/TakeSnapshot"
)
data := randomString(t, 16)
r.As(ownerName)
r.MakeDirectory(base)
r.Put(accessFile, access)
r.MakeDirectory(dir)
r.Put(file, data)
if r.Failed() {
t.Fatal(r.Diag())
}
// Take the snapshot.
r.As(snapshotUser)
r.MakeDirectory(snapshotDir)
if err := r.Err(); err != nil && !errors.Is(errors.Exist, err) {
// It's OK for the snapshot directory to exist already,
// as it won't be deleted after previous test runs.
t.Fatal(err)
}
r.Put(snapshotControlFile, "")
if r.Failed() {
t.Fatal(r.Diag())
}
// If the control file actually exists in snapshotDir, then this
// DirServer does not support snapshotting.
r.Get(snapshotControlFile)
if !r.Failed() {
if r.Data == "" {
t.Skip("Snapshotting not supported.")
}
t.Fatalf("Non-empty snapshot control file: %q.", r.Data)
}
// Verify snapshot was taken today and has the correct data in it.
r.As(ownerName)
snapPattern := snapshotDir + time.Now().UTC().Format("2006/01/02") + "/*"
// Use repeated Globs to find the snapshot; we can't use Watch because
// it is not supported for snapshots. See issue #536.
var snapshot upspin.PathName
for i := 0; i < 100; i++ {
r.Glob(snapPattern)
err := r.Err()
if err == nil && len(r.Entries) > 0 {
snapshot = r.Entries[0].Name
break
}
if err != nil && !errors.Is(errors.NotExist, err) {
t.Fatal(err)
}
time.Sleep(100 * time.Millisecond)
}
if snapshot == "" {
t.Fatalf("timed out waiting for snapshot in %q", snapPattern)
}
fileInSnapshot := path.Join(snapshot, "snapshot-test", "dir", "file")
// Ensure no one else can read this snapshotted file, even with a
// permissive Access file.
r.As(readerName)
r.DirLookup(fileInSnapshot)
if !r.Match(errors.E(errors.Private)) {
t.Fatal(r.Diag())
}
// WhichAccess for a snapshotted name returns nothing, even if the
// Access file exists in the path, which is the case here.
r.As(ownerName)
r.DirWhichAccess(fileInSnapshot)
if !r.GotNilEntry() {
t.Fatal(r.Diag())
}
// No one can delete snapshots.
r.Delete(fileInSnapshot)
if !r.Match(errors.E(errors.Permission)) {
t.Fatal(r.Diag())
}
// No one can overwrite a snapshot.
r.Put(fileInSnapshot, "yo")
if !r.Match(errors.E(errors.Permission)) {
t.Fatal(r.Diag())
}
}
func randomString(t *testing.T, size int) string {
buf := make([]byte, size)
_, err := rand.Read(buf)
if err != nil {
t.Fatal(err)
}
return fmt.Sprintf("%x", buf)
}