lib9p

Go 9P library.
Log | Files | Refs | LICENSE

test_fs.go (3852B)


      1 package lib9p
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"io/fs"
      7 	"path"
      8 	"strings"
      9 	"time"
     10 )
     11 
     12 const sleepTime = 1 * time.Second
     13 
     14 type TestFile struct {
     15 	Fsys     *TestFS
     16 	Parent   *TestFile
     17 	Children []*TestFile
     18 	Content  []byte
     19 	Reader   *bytes.Reader
     20 
     21 	St       Stat
     22 }
     23 
     24 func (f *TestFile) Stat() (*FileInfo, error) {
     25 	return &FileInfo{Stat: f.St}, nil
     26 }
     27 func (f *TestFile) Close() error {
     28 	f.Reader = nil
     29 	return nil
     30 }
     31 
     32 func (f *TestFile) Read(b []byte) (int, error) {
     33 	if f.Fsys.Slow {
     34 		time.Sleep(sleepTime)
     35 	}
     36 	return f.Reader.Read(b)
     37 }
     38 
     39 func (f *TestFile) ReadAt(b []byte, off int64) (n int, err error) {
     40 	if f.Fsys.Slow {
     41 		time.Sleep(sleepTime)
     42 	}
     43 	return f.Reader.ReadAt(b, off)
     44 }
     45 
     46 func (f *TestFile) ReadDir(n int) ([]*DirEntry, error) {
     47 	de := make([]*DirEntry, len(f.Children))
     48 	for i, c := range f.Children {
     49 		de[i], _ = c.Stat()
     50 	}
     51 	return de, nil
     52 }
     53 
     54 func (f *TestFile) WriteAt(p []byte, off int64) (int, error) {
     55 	if f.Fsys.Slow {
     56 		time.Sleep(sleepTime)
     57 	}
     58 	if f.Reader == nil {
     59 		return 0, fmt.Errorf("not open")
     60 	}
     61 	if off < 0 || off > int64(len(f.Content)) {
     62 		return 0, fmt.Errorf("bad offset")
     63 	}
     64 
     65 	if off+int64(len(p)) > int64(len(f.Content)) {
     66 		newcon := make([]byte, off+int64(len(p)))
     67 		copy(newcon, f.Content)
     68 		f.Content = newcon
     69 	}
     70 	copy(f.Content[off:], p)
     71 	f.Reader.Reset(f.Content)
     72 	return len(p), nil
     73 }
     74 
     75 type TestFS struct {
     76 	Root *TestFile
     77 	Slow bool
     78 }
     79 
     80 func (fs *TestFS) OpenFile(path string, omode OpenMode, perm fs.FileMode) (File, error) {
     81 	path = clean9path(path)
     82 	wnames := split9path(path)
     83 	f, err := fs.walk(wnames)
     84 	if err != nil {
     85 		return nil, fmt.Errorf("walk: %v", err)
     86 	}
     87 	f.Reader = bytes.NewReader(f.Content)
     88 	return f, nil
     89 }
     90 
     91 func (fs *TestFS) walk(wnames []string) (*TestFile, error) {
     92 	cwd := fs.Root
     93 L:
     94 	for i, name := range wnames {
     95 		for _, child := range cwd.Children {
     96 			if child.St.Name == name {
     97 				cwd = child
     98 				continue L
     99 			}
    100 		}
    101 		return nil, fmt.Errorf("%s not found", strings.Join(wnames[:i+1], "/"))
    102 	}
    103 	return cwd, nil
    104 }
    105 
    106 func clean9path(name string) string {
    107 	// TODO: eliminate leading ".."
    108 	name = path.Clean(name)
    109 	return name
    110 }
    111 
    112 func split9path(path string) []string {
    113 	if path == "." || path == "/" {
    114 		return []string{}
    115 	}
    116 	return strings.Split(path, "/")
    117 }
    118 
    119 var fsys *TestFS
    120 
    121 func init() {
    122 	fsys = &TestFS{
    123 		Root: &TestFile{
    124 			St: Stat{
    125 				Qid:  Qid{Path: 0, Type: QTDIR},
    126 				Mode: FileMode(fs.ModeDir | 0755),
    127 				Name: "root",
    128 				Uid:  "glenda",
    129 				Gid:  "glenda",
    130 				Muid: "glenda",
    131 			},
    132 			Children: []*TestFile{
    133 				&TestFile{
    134 					Content: []byte("a\n"),
    135 					St: Stat{
    136 						Qid:  Qid{Path: 1, Type: QTFILE},
    137 						Mode: FileMode(0644),
    138 						Name: "a",
    139 						Uid:  "glenda",
    140 						Gid:  "glenda",
    141 						Muid: "glenda",
    142 					},
    143 				},
    144 				&TestFile{
    145 					Content: []byte("b\n"),
    146 					St: Stat{
    147 						Qid:  Qid{Path: 2, Type: QTFILE},
    148 						Mode: FileMode(0400),
    149 						Name: "b",
    150 						Uid:  "ken",
    151 						Gid:  "ken",
    152 						Muid: "ken",
    153 					},
    154 				},
    155 				&TestFile{
    156 					St: Stat{
    157 						Qid:  Qid{Path: 3, Type: QTDIR},
    158 						Mode: FileMode(fs.ModeDir | 0755),
    159 						Name: "dir",
    160 						Uid:  "rob",
    161 						Gid:  "rob",
    162 						Muid: "rob",
    163 					},
    164 					Children: []*TestFile{
    165 						&TestFile{
    166 							Content: []byte("unko\n"),
    167 							St: Stat{
    168 								Qid:  Qid{Path: 4, Type: QTFILE},
    169 								Mode: FileMode(0666),
    170 								Name: "file",
    171 								Uid:  "brian",
    172 								Gid:  "brian",
    173 								Muid: "dennis",
    174 							},
    175 						},
    176 					},
    177 				},
    178 			},
    179 		},
    180 	}
    181 	SetFsysAndParent(fsys, nil)
    182 }
    183 
    184 // SetFsysAndParent sets file.fsys and file.parent for every file in the fsys.
    185 // Pass nil as file to setup entire file system.
    186 func SetFsysAndParent(fsys *TestFS, file *TestFile) {
    187 	if file == nil {
    188 		file = fsys.Root
    189 		file.Parent = fsys.Root
    190 		file.Fsys = fsys
    191 	}
    192 	for _, child := range file.Children {
    193 		child.Parent = file
    194 		child.Fsys = fsys
    195 		SetFsysAndParent(fsys, child)
    196 	}
    197 }