Skip to content

Commit 5d5f669

Browse files
committed
add storage pkg unit tests
1 parent 5e6ebdd commit 5d5f669

1 file changed

Lines changed: 196 additions & 0 deletions

File tree

internal/storage/storage_test.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package storage
2+
3+
import (
4+
"errors"
5+
"io"
6+
"os"
7+
"path/filepath"
8+
"testing"
9+
)
10+
11+
// fakeCloser implements namedCloser for closeLog tests.
12+
type fakeCloser struct {
13+
name string
14+
failClose bool
15+
}
16+
17+
func (f *fakeCloser) Close() error {
18+
if f.failClose {
19+
return errors.New("close failed")
20+
}
21+
return nil
22+
}
23+
24+
func (f *fakeCloser) Name() string {
25+
return f.name
26+
}
27+
28+
// fakeReadCloser implements io.Closer for closeSilent tests.
29+
type fakeReadCloser struct {
30+
failClose bool
31+
}
32+
33+
func (f *fakeReadCloser) Close() error {
34+
if f.failClose {
35+
return errors.New("close failed")
36+
}
37+
return nil
38+
}
39+
40+
// #################################################
41+
// ################# closeSilent ###################
42+
// #################################################
43+
func TestCloseSilent_SuccessfulClose(t *testing.T) {
44+
closeSilent(&fakeReadCloser{}) // must not panic
45+
}
46+
47+
func TestCloseSilent_ErrorIgnored(t *testing.T) {
48+
closeSilent(&fakeReadCloser{failClose: true}) // must not panic
49+
}
50+
51+
// #################################################
52+
// ################### closeLog ####################
53+
// #################################################
54+
func TestCloseLog_SuccessfulClose(t *testing.T) {
55+
closeLog(&fakeCloser{name: "testfile"}) // must not panic
56+
}
57+
58+
func TestCloseLog_ErrorLogged(t *testing.T) {
59+
// must not panic even when Close() fails (it logs instead)
60+
closeLog(&fakeCloser{name: "testfile", failClose: true})
61+
}
62+
63+
// #################################################
64+
// ################### moveFile ####################
65+
// #################################################
66+
func openTempRoot(t *testing.T) (string, *os.Root) {
67+
t.Helper()
68+
dir := t.TempDir()
69+
root, err := os.OpenRoot(dir)
70+
if err != nil {
71+
t.Fatalf("os.OpenRoot(%s): %v", dir, err)
72+
}
73+
t.Cleanup(func() { root.Close() })
74+
return dir, root
75+
}
76+
77+
func writeToRoot(t *testing.T, root *os.Root, name, content string) {
78+
t.Helper()
79+
f, err := root.Create(name)
80+
if err != nil {
81+
t.Fatalf("root.Create(%s): %v", name, err)
82+
}
83+
if _, err := io.WriteString(f, content); err != nil {
84+
f.Close()
85+
t.Fatalf("write %s: %v", name, err)
86+
}
87+
if err := f.Close(); err != nil {
88+
t.Fatalf("close %s: %v", name, err)
89+
}
90+
}
91+
92+
func readFromDir(t *testing.T, dir, name string) string {
93+
t.Helper()
94+
data, err := os.ReadFile(filepath.Join(dir, name))
95+
if err != nil {
96+
t.Fatalf("ReadFile(%s): %v", name, err)
97+
}
98+
return string(data)
99+
}
100+
101+
func TestMoveFile_Success(t *testing.T) {
102+
srcDir, srcRoot := openTempRoot(t)
103+
destDir, destRoot := openTempRoot(t)
104+
105+
writeToRoot(t, srcRoot, "src.zip", "zip contents")
106+
107+
if err := moveFile(srcRoot, destRoot, "src.zip", "dest.zip"); err != nil {
108+
t.Fatalf("moveFile: %v", err)
109+
}
110+
111+
if _, err := os.Stat(filepath.Join(srcDir, "src.zip")); !os.IsNotExist(err) {
112+
t.Error("expected source file to be gone after move")
113+
}
114+
115+
if got := readFromDir(t, destDir, "dest.zip"); got != "zip contents" {
116+
t.Errorf("content mismatch: want %q, got %q", "zip contents", got)
117+
}
118+
}
119+
120+
func TestMoveFile_PreservesContent(t *testing.T) {
121+
want := "dotfile data\nwith newlines\n\x00binary\xff"
122+
123+
_, srcRoot := openTempRoot(t)
124+
destDir, destRoot := openTempRoot(t)
125+
126+
writeToRoot(t, srcRoot, "data.zip", want)
127+
128+
if err := moveFile(srcRoot, destRoot, "data.zip", "out.zip"); err != nil {
129+
t.Fatalf("moveFile: %v", err)
130+
}
131+
132+
if got := readFromDir(t, destDir, "out.zip"); got != want {
133+
t.Errorf("content mismatch: want %q, got %q", want, got)
134+
}
135+
}
136+
137+
func TestMoveFile_DestNameDiffersFromSrc(t *testing.T) {
138+
_, srcRoot := openTempRoot(t)
139+
destDir, destRoot := openTempRoot(t)
140+
141+
writeToRoot(t, srcRoot, "original.zip", "data")
142+
143+
if err := moveFile(srcRoot, destRoot, "original.zip", "renamed.zip"); err != nil {
144+
t.Fatalf("moveFile: %v", err)
145+
}
146+
147+
if _, err := os.Stat(filepath.Join(destDir, "renamed.zip")); err != nil {
148+
t.Errorf("expected renamed.zip to exist: %v", err)
149+
}
150+
}
151+
152+
func TestMoveFile_EmptyFile(t *testing.T) {
153+
_, srcRoot := openTempRoot(t)
154+
destDir, destRoot := openTempRoot(t)
155+
156+
writeToRoot(t, srcRoot, "empty.zip", "")
157+
158+
if err := moveFile(srcRoot, destRoot, "empty.zip", "out.zip"); err != nil {
159+
t.Fatalf("moveFile: %v", err)
160+
}
161+
162+
if got := readFromDir(t, destDir, "out.zip"); got != "" {
163+
t.Errorf("expected empty content, got %q", got)
164+
}
165+
}
166+
167+
func TestMoveFile_SourceNotFound(t *testing.T) {
168+
_, srcRoot := openTempRoot(t)
169+
_, destRoot := openTempRoot(t)
170+
171+
err := moveFile(srcRoot, destRoot, "non-existent.zip", "dest.zip")
172+
if err == nil {
173+
t.Error("expected error for missing source file, got nil")
174+
}
175+
}
176+
177+
func TestMoveFile_SameRootDir(t *testing.T) {
178+
dir, root := openTempRoot(t)
179+
180+
// second root handle in the same dir
181+
root2, err := os.OpenRoot(dir)
182+
if err != nil {
183+
t.Fatalf("os.OpenRoot: %v", err)
184+
}
185+
t.Cleanup(func() { root2.Close() })
186+
187+
writeToRoot(t, root, "a.zip", "payload")
188+
189+
if err := moveFile(root, root2, "a.zip", "b.zip"); err != nil {
190+
t.Fatalf("moveFile within same dir: %v", err)
191+
}
192+
193+
if got := readFromDir(t, dir, "b.zip"); got != "payload" {
194+
t.Errorf("content mismatch: got %q", got)
195+
}
196+
}

0 commit comments

Comments
 (0)