| package fat32 |
| |
| import ( |
| "fmt" |
| "os" |
| "os/exec" |
| "strings" |
| "testing" |
| "time" |
| |
| "source.monogon.dev/metropolis/cli/pkg/datafile" |
| ) |
| |
| func testWithFsck(t *testing.T, rootInode Inode, opts Options) { |
| t.Helper() |
| fsckPath, err := datafile.ResolveRunfile("external/com_github_dosfstools_dosfstools/fsck") |
| if err != nil { |
| t.Fatalf("unable to get path to fsck: %v", err) |
| } |
| testFile, err := os.CreateTemp("", "fat32-fsck-test") |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer os.Remove(testFile.Name()) |
| if err := WriteFS(testFile, rootInode, opts); err != nil { |
| t.Fatalf("failed to write test FS: %v", err) |
| } |
| // Run fsck non-interactively (-n), disallow spaces in short file names (-S) |
| // as well as perform deep verification (-V) |
| // If the file system is OK (i.e. fsck does not want to fix it) it returns |
| // 0, otherwise 1. |
| fsckCmd := exec.Command(fsckPath, "-n", "-S", "-V", testFile.Name()) |
| result, err := fsckCmd.CombinedOutput() |
| if err != nil { |
| t.Errorf("fsck failed: %v", string(result)) |
| } |
| } |
| |
| func TestBasicFsck(t *testing.T) { |
| if os.Getenv("IN_KTEST") == "true" { |
| t.Skip("In ktest") |
| } |
| var largeString strings.Builder |
| for i := 0; i < 16384; i++ { |
| fmt.Fprintf(&largeString, "part%d", i) |
| } |
| // Test both common block sizes (512 and 4096 bytes) as well as the largest |
| // supported one (32K) |
| for _, blockSize := range []uint16{512, 4096, 32768} { |
| for _, fixed := range []string{"", "Fixed"} { |
| t.Run(fmt.Sprintf("BlockSize%d%v", blockSize, fixed), func(t *testing.T) { |
| rootInode := Inode{ |
| Attrs: AttrDirectory, |
| ModTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC), |
| CreateTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC), |
| } |
| files := []struct { |
| name string |
| path string |
| content string |
| }{ |
| {"FileInRoot", "test1.txt", "test1 content"}, |
| {"LongFileInRoot", "verylongtest1.txt", "test1 content long"}, |
| {"LongPath", "test1/test2/test3/test4/longdirname.ext/hello", "long path test content"}, |
| {"LargeFile", "test1/largefile.txt", largeString.String()}, |
| } |
| for _, c := range files { |
| err := rootInode.PlaceFile(c.path, strings.NewReader(c.content)) |
| if err != nil { |
| t.Errorf("failed to place file: %v", err) |
| } |
| } |
| opts := Options{ID: 1234, Label: "TEST", BlockSize: blockSize} |
| if fixed == "Fixed" { |
| // Use a block count that is slightly higher than the minimum |
| opts.BlockCount = 67000 |
| } |
| testWithFsck(t, rootInode, opts) |
| }) |
| } |
| } |
| } |
| |
| func TestLotsOfFilesFsck(t *testing.T) { |
| if os.Getenv("IN_KTEST") == "true" { |
| t.Skip("In ktest") |
| } |
| rootInode := Inode{ |
| Attrs: AttrDirectory, |
| ModTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC), |
| } |
| for i := 0; i < (32*1024)-2; i++ { |
| rootInode.Children = append(rootInode.Children, &Inode{ |
| Name: fmt.Sprintf("test%d", i), |
| Content: strings.NewReader("random test content"), |
| // Add some random attributes |
| Attrs: AttrHidden | AttrSystem, |
| // And a random ModTime |
| ModTime: time.Date(2022, 03, 04, 5, 6, 7, 8, time.UTC), |
| }) |
| } |
| testWithFsck(t, rootInode, Options{ID: 1234, Label: "TEST"}) |
| } |