forked from zuoyebang/bitalostable
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilenames_test.go
130 lines (110 loc) · 3.22 KB
/
filenames_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2020 The LevelDB-Go and Pebble and Bitalostored 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 bitalostable
import (
"testing"
"github.com/cockroachdb/errors"
"github.com/stretchr/testify/require"
"github.com/zuoyebang/bitalostable/internal/base"
"github.com/zuoyebang/bitalostable/vfs"
)
// TestSetCurrentFileCrash tests a crash that occurs during
// a MANIFEST roll, leaving the temporary CURRENT file on
// the filesystem. These temporary files should be cleaned
// up on Open.
func TestSetCurrentFileCrash(t *testing.T) {
mem := vfs.NewMem()
// Initialize a fresh database to write the initial MANIFEST.
{
d, err := Open("", &Options{FS: mem})
require.NoError(t, err)
require.NoError(t, d.Close())
}
// Open the database again, this time with a FS that
// errors on Rename and a tiny max manifest file size
// to force manifest rolls.
{
wantErr := errors.New("rename error")
_, err := Open("", &Options{
FS: renameErrorFS{FS: mem, err: wantErr},
Logger: noFatalLogger{t: t},
MaxManifestFileSize: 1,
L0CompactionThreshold: 10,
})
// Open should fail during a manifest roll,
// leaving a temp dir on the filesystem.
if !errors.Is(err, wantErr) {
t.Fatal(err)
}
}
// A temp file should be left on the filesystem
// from the failed Rename of the CURRENT file.
if temps := allTempFiles(t, mem); len(temps) == 0 {
t.Fatal("no temp files on the filesystem")
}
// Open the database a third time with a normal
// filesystem again. It should clean up any temp
// files on Open.
{
d, err := Open("", &Options{
FS: mem,
MaxManifestFileSize: 1,
L0CompactionThreshold: 10,
})
require.NoError(t, err)
require.NoError(t, d.Close())
if temps := allTempFiles(t, mem); len(temps) > 0 {
t.Fatalf("temporary files still on disk: %#v\n", temps)
}
}
}
func allTempFiles(t *testing.T, fs vfs.FS) []string {
var files []string
ls, err := fs.List("")
require.NoError(t, err)
for _, f := range ls {
ft, _, ok := base.ParseFilename(fs, f)
if ok && ft == fileTypeTemp {
files = append(files, f)
}
}
return files
}
type renameErrorFS struct {
vfs.FS
err error
}
func (fs renameErrorFS) Rename(oldname string, newname string) error {
return fs.err
}
// noFatalLogger implements Logger, logging to the contained
// *testing.T. Notably it does not panic on calls to Fatalf
// to enable unit tests of fatal logic.
type noFatalLogger struct {
t *testing.T
}
func (l noFatalLogger) Info(args ...interface{}) {
l.t.Log(args...)
}
func (l noFatalLogger) Warn(args ...interface{}) {
l.t.Error(args...)
}
func (l noFatalLogger) Error(args ...interface{}) {
l.t.Error(args...)
}
func (l noFatalLogger) Infof(format string, args ...interface{}) {
l.t.Logf(format, args...)
}
func (l noFatalLogger) Warnf(format string, args ...interface{}) {
l.t.Errorf(format, args...)
}
func (l noFatalLogger) Errorf(format string, args ...interface{}) {
l.t.Errorf(format, args...)
}
func (l noFatalLogger) Fatalf(format string, args ...interface{}) {
l.t.Logf(format, args...)
}
func (l noFatalLogger) Cost(arg ...interface{}) func() {
return func() {}
}