The problem
I rewrote my tests to use an fstest.MapFS
, defined like this
Simple, and yet when I ran a test against it, I received this error:
contentRoot := fstest.MapFS{
"/parentDir/index.html": &fstest.MapFile{Data: []byte("content"), Mode: 0o755},
"/parentDir/childDir/1-2-3.html": &fstest.MapFile{Data: []byte("other content"`), Mode: 0o755},
}
2024/03/27 19:42:59 http: panic serving [::1]:57135: open parentDir: file does not exist
The setup
I wrote this comment a few days ago and haven't thought much about it since:
pagePath is retrieved from an http GET, and always starts with a "/"; I don't want to be seeking for an absolute
path inside the os.DirFS because the file won't be found.
// /index.html becomes index.html
// /articles/page.html becomes articles/page.html
// without this the paths aren't found properly inside the fs.
pagePath = strings.TrimPrefix(pagePath, "/")
pageContent, err := fs.ReadFile(a.SiteFiles, pagePath)
ReadFile dispatches to the a.SiteFiles implementation of the Open function, so the os.DirFS
controls lookup of the file. You
can see that in the official source:
func ReadFile(fsys FS, name string) ([]byte, error) {
if fsys, ok := fsys.(ReadFileFS); ok {
return fsys.ReadFile(name)
}
file, err := fsys.Open(name)
What's the misunderstanding?
This one took me a couple of hours to finally understand.
An fstest.MapFS
is a hash map. Its implementation of Open()
is very simple:
It simply looks up the key in the hashmap, and I was manipulating that key to remove a leading slash.
file := fsys[name]
- reference in the go source code.
What's the fix?
Once I understood that the path in the fstest.MapFS
is only a map key, I realised it does not need to be an absolute path.
I redefined it like this and got my tests passing:
contentRoot := fstest.MapFS{
"parentDir/index.html": &fstest.MapFile{Data: []byte("content"), Mode: 0o755},
"parentDir/childDir/1-2-3.html": &fstest.MapFile{Data: []byte("other content"`), Mode: 0o755},
}