forked from TrueCloudLab/restic
Vendor dependencies with dep
This commit is contained in:
parent
df8a5792f1
commit
91edebf1fe
1691 changed files with 466360 additions and 0 deletions
731
vendor/golang.org/x/net/webdav/lock_test.go
generated
vendored
Normal file
731
vendor/golang.org/x/net/webdav/lock_test.go
generated
vendored
Normal file
|
@ -0,0 +1,731 @@
|
|||
// Copyright 2014 The Go 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 webdav
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWalkToRoot(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
want []string
|
||||
}{{
|
||||
"/a/b/c/d",
|
||||
[]string{
|
||||
"/a/b/c/d",
|
||||
"/a/b/c",
|
||||
"/a/b",
|
||||
"/a",
|
||||
"/",
|
||||
},
|
||||
}, {
|
||||
"/a",
|
||||
[]string{
|
||||
"/a",
|
||||
"/",
|
||||
},
|
||||
}, {
|
||||
"/",
|
||||
[]string{
|
||||
"/",
|
||||
},
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
var got []string
|
||||
if !walkToRoot(tc.name, func(name0 string, first bool) bool {
|
||||
if first != (len(got) == 0) {
|
||||
t.Errorf("name=%q: first=%t but len(got)==%d", tc.name, first, len(got))
|
||||
return false
|
||||
}
|
||||
got = append(got, name0)
|
||||
return true
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("name=%q:\ngot %q\nwant %q", tc.name, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lockTestDurations = []time.Duration{
|
||||
infiniteTimeout, // infiniteTimeout means to never expire.
|
||||
0, // A zero duration means to expire immediately.
|
||||
100 * time.Hour, // A very large duration will not expire in these tests.
|
||||
}
|
||||
|
||||
// lockTestNames are the names of a set of mutually compatible locks. For each
|
||||
// name fragment:
|
||||
// - _ means no explicit lock.
|
||||
// - i means a infinite-depth lock,
|
||||
// - z means a zero-depth lock,
|
||||
var lockTestNames = []string{
|
||||
"/_/_/_/_/z",
|
||||
"/_/_/i",
|
||||
"/_/z",
|
||||
"/_/z/i",
|
||||
"/_/z/z",
|
||||
"/_/z/_/i",
|
||||
"/_/z/_/z",
|
||||
"/i",
|
||||
"/z",
|
||||
"/z/_/i",
|
||||
"/z/_/z",
|
||||
}
|
||||
|
||||
func lockTestZeroDepth(name string) bool {
|
||||
switch name[len(name)-1] {
|
||||
case 'i':
|
||||
return false
|
||||
case 'z':
|
||||
return true
|
||||
}
|
||||
panic(fmt.Sprintf("lock name %q did not end with 'i' or 'z'", name))
|
||||
}
|
||||
|
||||
func TestMemLSCanCreate(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
m := NewMemLS().(*memLS)
|
||||
|
||||
for _, name := range lockTestNames {
|
||||
_, err := m.Create(now, LockDetails{
|
||||
Root: name,
|
||||
Duration: infiniteTimeout,
|
||||
ZeroDepth: lockTestZeroDepth(name),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("creating lock for %q: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
wantCanCreate := func(name string, zeroDepth bool) bool {
|
||||
for _, n := range lockTestNames {
|
||||
switch {
|
||||
case n == name:
|
||||
// An existing lock has the same name as the proposed lock.
|
||||
return false
|
||||
case strings.HasPrefix(n, name):
|
||||
// An existing lock would be a child of the proposed lock,
|
||||
// which conflicts if the proposed lock has infinite depth.
|
||||
if !zeroDepth {
|
||||
return false
|
||||
}
|
||||
case strings.HasPrefix(name, n):
|
||||
// An existing lock would be an ancestor of the proposed lock,
|
||||
// which conflicts if the ancestor has infinite depth.
|
||||
if n[len(n)-1] == 'i' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var check func(int, string)
|
||||
check = func(recursion int, name string) {
|
||||
for _, zeroDepth := range []bool{false, true} {
|
||||
got := m.canCreate(name, zeroDepth)
|
||||
want := wantCanCreate(name, zeroDepth)
|
||||
if got != want {
|
||||
t.Errorf("canCreate name=%q zeroDepth=%t: got %t, want %t", name, zeroDepth, got, want)
|
||||
}
|
||||
}
|
||||
if recursion == 6 {
|
||||
return
|
||||
}
|
||||
if name != "/" {
|
||||
name += "/"
|
||||
}
|
||||
for _, c := range "_iz" {
|
||||
check(recursion+1, name+string(c))
|
||||
}
|
||||
}
|
||||
check(0, "/")
|
||||
}
|
||||
|
||||
func TestMemLSLookup(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
m := NewMemLS().(*memLS)
|
||||
|
||||
badToken := m.nextToken()
|
||||
t.Logf("badToken=%q", badToken)
|
||||
|
||||
for _, name := range lockTestNames {
|
||||
token, err := m.Create(now, LockDetails{
|
||||
Root: name,
|
||||
Duration: infiniteTimeout,
|
||||
ZeroDepth: lockTestZeroDepth(name),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("creating lock for %q: %v", name, err)
|
||||
}
|
||||
t.Logf("%-15q -> node=%p token=%q", name, m.byName[name], token)
|
||||
}
|
||||
|
||||
baseNames := append([]string{"/a", "/b/c"}, lockTestNames...)
|
||||
for _, baseName := range baseNames {
|
||||
for _, suffix := range []string{"", "/0", "/1/2/3"} {
|
||||
name := baseName + suffix
|
||||
|
||||
goodToken := ""
|
||||
base := m.byName[baseName]
|
||||
if base != nil && (suffix == "" || !lockTestZeroDepth(baseName)) {
|
||||
goodToken = base.token
|
||||
}
|
||||
|
||||
for _, token := range []string{badToken, goodToken} {
|
||||
if token == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
got := m.lookup(name, Condition{Token: token})
|
||||
want := base
|
||||
if token == badToken {
|
||||
want = nil
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("name=%-20qtoken=%q (bad=%t): got %p, want %p",
|
||||
name, token, token == badToken, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemLSConfirm(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
m := NewMemLS().(*memLS)
|
||||
alice, err := m.Create(now, LockDetails{
|
||||
Root: "/alice",
|
||||
Duration: infiniteTimeout,
|
||||
ZeroDepth: false,
|
||||
})
|
||||
tweedle, err := m.Create(now, LockDetails{
|
||||
Root: "/tweedle",
|
||||
Duration: infiniteTimeout,
|
||||
ZeroDepth: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Create: %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Create: inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
// Test a mismatch between name and condition.
|
||||
_, err = m.Confirm(now, "/tweedle/dee", "", Condition{Token: alice})
|
||||
if err != ErrConfirmationFailed {
|
||||
t.Fatalf("Confirm (mismatch): got %v, want ErrConfirmationFailed", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Confirm (mismatch): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
// Test two names (that fall under the same lock) in the one Confirm call.
|
||||
release, err := m.Confirm(now, "/tweedle/dee", "/tweedle/dum", Condition{Token: tweedle})
|
||||
if err != nil {
|
||||
t.Fatalf("Confirm (twins): %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Confirm (twins): inconsistent state: %v", err)
|
||||
}
|
||||
release()
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("release (twins): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
// Test the same two names in overlapping Confirm / release calls.
|
||||
releaseDee, err := m.Confirm(now, "/tweedle/dee", "", Condition{Token: tweedle})
|
||||
if err != nil {
|
||||
t.Fatalf("Confirm (sequence #0): %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Confirm (sequence #0): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
_, err = m.Confirm(now, "/tweedle/dum", "", Condition{Token: tweedle})
|
||||
if err != ErrConfirmationFailed {
|
||||
t.Fatalf("Confirm (sequence #1): got %v, want ErrConfirmationFailed", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Confirm (sequence #1): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
releaseDee()
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("release (sequence #2): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
releaseDum, err := m.Confirm(now, "/tweedle/dum", "", Condition{Token: tweedle})
|
||||
if err != nil {
|
||||
t.Fatalf("Confirm (sequence #3): %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Confirm (sequence #3): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
// Test that you can't unlock a held lock.
|
||||
err = m.Unlock(now, tweedle)
|
||||
if err != ErrLocked {
|
||||
t.Fatalf("Unlock (sequence #4): got %v, want ErrLocked", err)
|
||||
}
|
||||
|
||||
releaseDum()
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("release (sequence #5): inconsistent state: %v", err)
|
||||
}
|
||||
|
||||
err = m.Unlock(now, tweedle)
|
||||
if err != nil {
|
||||
t.Fatalf("Unlock (sequence #6): %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Unlock (sequence #6): inconsistent state: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemLSNonCanonicalRoot(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
m := NewMemLS().(*memLS)
|
||||
token, err := m.Create(now, LockDetails{
|
||||
Root: "/foo/./bar//",
|
||||
Duration: 1 * time.Second,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Create: %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Create: inconsistent state: %v", err)
|
||||
}
|
||||
if err := m.Unlock(now, token); err != nil {
|
||||
t.Fatalf("Unlock: %v", err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("Unlock: inconsistent state: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemLSExpiry(t *testing.T) {
|
||||
m := NewMemLS().(*memLS)
|
||||
testCases := []string{
|
||||
"setNow 0",
|
||||
"create /a.5",
|
||||
"want /a.5",
|
||||
"create /c.6",
|
||||
"want /a.5 /c.6",
|
||||
"create /a/b.7",
|
||||
"want /a.5 /a/b.7 /c.6",
|
||||
"setNow 4",
|
||||
"want /a.5 /a/b.7 /c.6",
|
||||
"setNow 5",
|
||||
"want /a/b.7 /c.6",
|
||||
"setNow 6",
|
||||
"want /a/b.7",
|
||||
"setNow 7",
|
||||
"want ",
|
||||
"setNow 8",
|
||||
"want ",
|
||||
"create /a.12",
|
||||
"create /b.13",
|
||||
"create /c.15",
|
||||
"create /a/d.16",
|
||||
"want /a.12 /a/d.16 /b.13 /c.15",
|
||||
"refresh /a.14",
|
||||
"want /a.14 /a/d.16 /b.13 /c.15",
|
||||
"setNow 12",
|
||||
"want /a.14 /a/d.16 /b.13 /c.15",
|
||||
"setNow 13",
|
||||
"want /a.14 /a/d.16 /c.15",
|
||||
"setNow 14",
|
||||
"want /a/d.16 /c.15",
|
||||
"refresh /a/d.20",
|
||||
"refresh /c.20",
|
||||
"want /a/d.20 /c.20",
|
||||
"setNow 20",
|
||||
"want ",
|
||||
}
|
||||
|
||||
tokens := map[string]string{}
|
||||
zTime := time.Unix(0, 0)
|
||||
now := zTime
|
||||
for i, tc := range testCases {
|
||||
j := strings.IndexByte(tc, ' ')
|
||||
if j < 0 {
|
||||
t.Fatalf("test case #%d %q: invalid command", i, tc)
|
||||
}
|
||||
op, arg := tc[:j], tc[j+1:]
|
||||
switch op {
|
||||
default:
|
||||
t.Fatalf("test case #%d %q: invalid operation %q", i, tc, op)
|
||||
|
||||
case "create", "refresh":
|
||||
parts := strings.Split(arg, ".")
|
||||
if len(parts) != 2 {
|
||||
t.Fatalf("test case #%d %q: invalid create", i, tc)
|
||||
}
|
||||
root := parts[0]
|
||||
d, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
t.Fatalf("test case #%d %q: invalid duration", i, tc)
|
||||
}
|
||||
dur := time.Unix(0, 0).Add(time.Duration(d) * time.Second).Sub(now)
|
||||
|
||||
switch op {
|
||||
case "create":
|
||||
token, err := m.Create(now, LockDetails{
|
||||
Root: root,
|
||||
Duration: dur,
|
||||
ZeroDepth: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("test case #%d %q: Create: %v", i, tc, err)
|
||||
}
|
||||
tokens[root] = token
|
||||
|
||||
case "refresh":
|
||||
token := tokens[root]
|
||||
if token == "" {
|
||||
t.Fatalf("test case #%d %q: no token for %q", i, tc, root)
|
||||
}
|
||||
got, err := m.Refresh(now, token, dur)
|
||||
if err != nil {
|
||||
t.Fatalf("test case #%d %q: Refresh: %v", i, tc, err)
|
||||
}
|
||||
want := LockDetails{
|
||||
Root: root,
|
||||
Duration: dur,
|
||||
ZeroDepth: true,
|
||||
}
|
||||
if got != want {
|
||||
t.Fatalf("test case #%d %q:\ngot %v\nwant %v", i, tc, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
case "setNow":
|
||||
d, err := strconv.Atoi(arg)
|
||||
if err != nil {
|
||||
t.Fatalf("test case #%d %q: invalid duration", i, tc)
|
||||
}
|
||||
now = time.Unix(0, 0).Add(time.Duration(d) * time.Second)
|
||||
|
||||
case "want":
|
||||
m.mu.Lock()
|
||||
m.collectExpiredNodes(now)
|
||||
got := make([]string, 0, len(m.byToken))
|
||||
for _, n := range m.byToken {
|
||||
got = append(got, fmt.Sprintf("%s.%d",
|
||||
n.details.Root, n.expiry.Sub(zTime)/time.Second))
|
||||
}
|
||||
m.mu.Unlock()
|
||||
sort.Strings(got)
|
||||
want := []string{}
|
||||
if arg != "" {
|
||||
want = strings.Split(arg, " ")
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("test case #%d %q:\ngot %q\nwant %q", i, tc, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("test case #%d %q: inconsistent state: %v", i, tc, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemLS(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
m := NewMemLS().(*memLS)
|
||||
rng := rand.New(rand.NewSource(0))
|
||||
tokens := map[string]string{}
|
||||
nConfirm, nCreate, nRefresh, nUnlock := 0, 0, 0, 0
|
||||
const N = 2000
|
||||
|
||||
for i := 0; i < N; i++ {
|
||||
name := lockTestNames[rng.Intn(len(lockTestNames))]
|
||||
duration := lockTestDurations[rng.Intn(len(lockTestDurations))]
|
||||
confirmed, unlocked := false, false
|
||||
|
||||
// If the name was already locked, we randomly confirm/release, refresh
|
||||
// or unlock it. Otherwise, we create a lock.
|
||||
token := tokens[name]
|
||||
if token != "" {
|
||||
switch rng.Intn(3) {
|
||||
case 0:
|
||||
confirmed = true
|
||||
nConfirm++
|
||||
release, err := m.Confirm(now, name, "", Condition{Token: token})
|
||||
if err != nil {
|
||||
t.Fatalf("iteration #%d: Confirm %q: %v", i, name, err)
|
||||
}
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("iteration #%d: inconsistent state: %v", i, err)
|
||||
}
|
||||
release()
|
||||
|
||||
case 1:
|
||||
nRefresh++
|
||||
if _, err := m.Refresh(now, token, duration); err != nil {
|
||||
t.Fatalf("iteration #%d: Refresh %q: %v", i, name, err)
|
||||
}
|
||||
|
||||
case 2:
|
||||
unlocked = true
|
||||
nUnlock++
|
||||
if err := m.Unlock(now, token); err != nil {
|
||||
t.Fatalf("iteration #%d: Unlock %q: %v", i, name, err)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
nCreate++
|
||||
var err error
|
||||
token, err = m.Create(now, LockDetails{
|
||||
Root: name,
|
||||
Duration: duration,
|
||||
ZeroDepth: lockTestZeroDepth(name),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("iteration #%d: Create %q: %v", i, name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !confirmed {
|
||||
if duration == 0 || unlocked {
|
||||
// A zero-duration lock should expire immediately and is
|
||||
// effectively equivalent to being unlocked.
|
||||
tokens[name] = ""
|
||||
} else {
|
||||
tokens[name] = token
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.consistent(); err != nil {
|
||||
t.Fatalf("iteration #%d: inconsistent state: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
if nConfirm < N/10 {
|
||||
t.Fatalf("too few Confirm calls: got %d, want >= %d", nConfirm, N/10)
|
||||
}
|
||||
if nCreate < N/10 {
|
||||
t.Fatalf("too few Create calls: got %d, want >= %d", nCreate, N/10)
|
||||
}
|
||||
if nRefresh < N/10 {
|
||||
t.Fatalf("too few Refresh calls: got %d, want >= %d", nRefresh, N/10)
|
||||
}
|
||||
if nUnlock < N/10 {
|
||||
t.Fatalf("too few Unlock calls: got %d, want >= %d", nUnlock, N/10)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *memLS) consistent() error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
// If m.byName is non-empty, then it must contain an entry for the root "/",
|
||||
// and its refCount should equal the number of locked nodes.
|
||||
if len(m.byName) > 0 {
|
||||
n := m.byName["/"]
|
||||
if n == nil {
|
||||
return fmt.Errorf(`non-empty m.byName does not contain the root "/"`)
|
||||
}
|
||||
if n.refCount != len(m.byToken) {
|
||||
return fmt.Errorf("root node refCount=%d, differs from len(m.byToken)=%d", n.refCount, len(m.byToken))
|
||||
}
|
||||
}
|
||||
|
||||
for name, n := range m.byName {
|
||||
// The map keys should be consistent with the node's copy of the key.
|
||||
if n.details.Root != name {
|
||||
return fmt.Errorf("node name %q != byName map key %q", n.details.Root, name)
|
||||
}
|
||||
|
||||
// A name must be clean, and start with a "/".
|
||||
if len(name) == 0 || name[0] != '/' {
|
||||
return fmt.Errorf(`node name %q does not start with "/"`, name)
|
||||
}
|
||||
if name != path.Clean(name) {
|
||||
return fmt.Errorf(`node name %q is not clean`, name)
|
||||
}
|
||||
|
||||
// A node's refCount should be positive.
|
||||
if n.refCount <= 0 {
|
||||
return fmt.Errorf("non-positive refCount for node at name %q", name)
|
||||
}
|
||||
|
||||
// A node's refCount should be the number of self-or-descendents that
|
||||
// are locked (i.e. have a non-empty token).
|
||||
var list []string
|
||||
for name0, n0 := range m.byName {
|
||||
// All of lockTestNames' name fragments are one byte long: '_', 'i' or 'z',
|
||||
// so strings.HasPrefix is equivalent to self-or-descendent name match.
|
||||
// We don't have to worry about "/foo/bar" being a false positive match
|
||||
// for "/foo/b".
|
||||
if strings.HasPrefix(name0, name) && n0.token != "" {
|
||||
list = append(list, name0)
|
||||
}
|
||||
}
|
||||
if n.refCount != len(list) {
|
||||
sort.Strings(list)
|
||||
return fmt.Errorf("node at name %q has refCount %d but locked self-or-descendents are %q (len=%d)",
|
||||
name, n.refCount, list, len(list))
|
||||
}
|
||||
|
||||
// A node n is in m.byToken if it has a non-empty token.
|
||||
if n.token != "" {
|
||||
if _, ok := m.byToken[n.token]; !ok {
|
||||
return fmt.Errorf("node at name %q has token %q but not in m.byToken", name, n.token)
|
||||
}
|
||||
}
|
||||
|
||||
// A node n is in m.byExpiry if it has a non-negative byExpiryIndex.
|
||||
if n.byExpiryIndex >= 0 {
|
||||
if n.byExpiryIndex >= len(m.byExpiry) {
|
||||
return fmt.Errorf("node at name %q has byExpiryIndex %d but m.byExpiry has length %d", name, n.byExpiryIndex, len(m.byExpiry))
|
||||
}
|
||||
if n != m.byExpiry[n.byExpiryIndex] {
|
||||
return fmt.Errorf("node at name %q has byExpiryIndex %d but that indexes a different node", name, n.byExpiryIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for token, n := range m.byToken {
|
||||
// The map keys should be consistent with the node's copy of the key.
|
||||
if n.token != token {
|
||||
return fmt.Errorf("node token %q != byToken map key %q", n.token, token)
|
||||
}
|
||||
|
||||
// Every node in m.byToken is in m.byName.
|
||||
if _, ok := m.byName[n.details.Root]; !ok {
|
||||
return fmt.Errorf("node at name %q in m.byToken but not in m.byName", n.details.Root)
|
||||
}
|
||||
}
|
||||
|
||||
for i, n := range m.byExpiry {
|
||||
// The slice indices should be consistent with the node's copy of the index.
|
||||
if n.byExpiryIndex != i {
|
||||
return fmt.Errorf("node byExpiryIndex %d != byExpiry slice index %d", n.byExpiryIndex, i)
|
||||
}
|
||||
|
||||
// Every node in m.byExpiry is in m.byName.
|
||||
if _, ok := m.byName[n.details.Root]; !ok {
|
||||
return fmt.Errorf("node at name %q in m.byExpiry but not in m.byName", n.details.Root)
|
||||
}
|
||||
|
||||
// No node in m.byExpiry should be held.
|
||||
if n.held {
|
||||
return fmt.Errorf("node at name %q in m.byExpiry is held", n.details.Root)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestParseTimeout(t *testing.T) {
|
||||
testCases := []struct {
|
||||
s string
|
||||
want time.Duration
|
||||
wantErr error
|
||||
}{{
|
||||
"",
|
||||
infiniteTimeout,
|
||||
nil,
|
||||
}, {
|
||||
"Infinite",
|
||||
infiniteTimeout,
|
||||
nil,
|
||||
}, {
|
||||
"Infinitesimal",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"infinite",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second-0",
|
||||
0 * time.Second,
|
||||
nil,
|
||||
}, {
|
||||
"Second-123",
|
||||
123 * time.Second,
|
||||
nil,
|
||||
}, {
|
||||
" Second-456 ",
|
||||
456 * time.Second,
|
||||
nil,
|
||||
}, {
|
||||
"Second-4100000000",
|
||||
4100000000 * time.Second,
|
||||
nil,
|
||||
}, {
|
||||
"junk",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second-",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second--1",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second--123",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second-+123",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second-0x123",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"second-123",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
"Second-4294967295",
|
||||
4294967295 * time.Second,
|
||||
nil,
|
||||
}, {
|
||||
// Section 10.7 says that "The timeout value for TimeType "Second"
|
||||
// must not be greater than 2^32-1."
|
||||
"Second-4294967296",
|
||||
0,
|
||||
errInvalidTimeout,
|
||||
}, {
|
||||
// This test case comes from section 9.10.9 of the spec. It says,
|
||||
//
|
||||
// "In this request, the client has specified that it desires an
|
||||
// infinite-length lock, if available, otherwise a timeout of 4.1
|
||||
// billion seconds, if available."
|
||||
//
|
||||
// The Go WebDAV package always supports infinite length locks,
|
||||
// and ignores the fallback after the comma.
|
||||
"Infinite, Second-4100000000",
|
||||
infiniteTimeout,
|
||||
nil,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
got, gotErr := parseTimeout(tc.s)
|
||||
if got != tc.want || gotErr != tc.wantErr {
|
||||
t.Errorf("parsing %q:\ngot %v, %v\nwant %v, %v", tc.s, got, gotErr, tc.want, tc.wantErr)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue