blob: 687504a310444481f3909645c32ed62f795c50e2 [file] [log] [blame]
Lorenz Brunbd2ce6d2022-07-22 00:00:13 +00001package fat32
2
3import (
4 "fmt"
5 "os"
6 "os/exec"
7 "strings"
8 "testing"
9 "time"
10
11 "source.monogon.dev/metropolis/cli/pkg/datafile"
12)
13
14func testWithFsck(t *testing.T, rootInode Inode, opts Options) {
15 t.Helper()
16 fsckPath, err := datafile.ResolveRunfile("external/com_github_dosfstools_dosfstools/fsck")
17 if err != nil {
18 t.Fatalf("unable to get path to fsck: %v", err)
19 }
20 testFile, err := os.CreateTemp("", "fat32-fsck-test")
21 if err != nil {
22 t.Fatal(err)
23 }
24 defer os.Remove(testFile.Name())
25 if err := WriteFS(testFile, rootInode, opts); err != nil {
26 t.Fatalf("failed to write test FS: %v", err)
27 }
28 // Run fsck non-interactively (-n), disallow spaces in short file names (-S)
29 // as well as perform deep verification (-V)
30 // If the file system is OK (i.e. fsck does not want to fix it) it returns
31 // 0, otherwise 1.
32 fsckCmd := exec.Command(fsckPath, "-n", "-S", "-V", testFile.Name())
33 result, err := fsckCmd.CombinedOutput()
34 if err != nil {
35 t.Errorf("fsck failed: %v", string(result))
36 }
37}
38
39func TestBasicFsck(t *testing.T) {
40 if os.Getenv("IN_KTEST") == "true" {
41 t.Skip("In ktest")
42 }
43 var largeString strings.Builder
44 for i := 0; i < 16384; i++ {
45 fmt.Fprintf(&largeString, "part%d", i)
46 }
47 // Test both common block sizes (512 and 4096 bytes) as well as the largest
48 // supported one (32K)
49 for _, blockSize := range []uint16{512, 4096, 32768} {
50 for _, fixed := range []string{"", "Fixed"} {
51 t.Run(fmt.Sprintf("BlockSize%d%v", blockSize, fixed), func(t *testing.T) {
52 rootInode := Inode{
53 Attrs: AttrDirectory,
54 ModTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC),
55 CreateTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC),
56 }
57 files := []struct {
58 name string
59 path string
60 content string
61 }{
62 {"FileInRoot", "test1.txt", "test1 content"},
63 {"LongFileInRoot", "verylongtest1.txt", "test1 content long"},
64 {"LongPath", "test1/test2/test3/test4/longdirname.ext/hello", "long path test content"},
65 {"LargeFile", "test1/largefile.txt", largeString.String()},
66 }
67 for _, c := range files {
68 err := rootInode.PlaceFile(c.path, strings.NewReader(c.content))
69 if err != nil {
70 t.Errorf("failed to place file: %v", err)
71 }
72 }
73 opts := Options{ID: 1234, Label: "TEST", BlockSize: blockSize}
74 if fixed == "Fixed" {
75 // Use a block count that is slightly higher than the minimum
76 opts.BlockCount = 67000
77 }
78 testWithFsck(t, rootInode, opts)
79 })
80 }
81 }
82}
83
84func TestLotsOfFilesFsck(t *testing.T) {
85 if os.Getenv("IN_KTEST") == "true" {
86 t.Skip("In ktest")
87 }
88 rootInode := Inode{
89 Attrs: AttrDirectory,
90 ModTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC),
91 }
92 for i := 0; i < (32*1024)-2; i++ {
93 rootInode.Children = append(rootInode.Children, &Inode{
94 Name: fmt.Sprintf("test%d", i),
95 Content: strings.NewReader("random test content"),
96 // Add some random attributes
97 Attrs: AttrHidden | AttrSystem,
98 // And a random ModTime
99 ModTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC),
100 })
101 }
102 testWithFsck(t, rootInode, Options{ID: 1234, Label: "TEST"})
103}