blob: 687504a310444481f3909645c32ed62f795c50e2 [file] [log] [blame] [edit]
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"})
}