-
Notifications
You must be signed in to change notification settings - Fork 456
/
filenames_test.go
111 lines (96 loc) · 2.84 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
// Copyright 2020 The LevelDB-Go and Pebble 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 pebble
import (
"testing"
"github.com/cockroachdb/errors"
"github.com/cockroachdb/pebble/internal/base"
"github.com/cockroachdb/pebble/vfs"
"github.com/stretchr/testify/require"
)
// 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,
Logger: testLogger{t},
})
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) Infof(format string, args ...interface{}) {
l.t.Logf(format, args...)
}
func (l noFatalLogger) Errorf(format string, args ...interface{}) {
l.t.Logf(format, args...)
}
func (l noFatalLogger) Fatalf(format string, args ...interface{}) {
l.t.Logf(format, args...)
}