diff --git a/js/initcontext.go b/js/initcontext.go index 52e10cc9809..82ba3fd560a 100644 --- a/js/initcontext.go +++ b/js/initcontext.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/url" - "path/filepath" "github.com/dop251/goja" "github.com/sirupsen/logrus" @@ -20,20 +19,7 @@ const cantBeUsedOutsideInitContextMsg = `the "%s" function is only available in // contents of a file. If the second argument is "b" it returns an ArrayBuffer // instance, otherwise a string representation. func openImpl(rt *goja.Runtime, fs fsext.Fs, basePWD *url.URL, filename string, args ...string) (goja.Value, error) { - // Here IsAbs should be enough but unfortunately it doesn't handle absolute paths starting from - // the current drive on windows like `\users\noname\...`. Also it makes it more easy to test and - // will probably be need for archive execution under windows if always consider '/...' as an - // absolute path. - if filename[0] != '/' && filename[0] != '\\' && !filepath.IsAbs(filename) { - filename = filepath.Join(basePWD.Path, filename) - } - filename = filepath.Clean(filename) - - if filename[0:1] != fsext.FilePathSeparator { - filename = fsext.FilePathSeparator + filename - } - - data, err := readFile(fs, filename) + data, err := readFile(fs, fsext.Abs(basePWD.Path, filename)) if err != nil { return nil, err } diff --git a/lib/fsext/filepath.go b/lib/fsext/filepath.go index 322eac2d74a..230f7c506c0 100644 --- a/lib/fsext/filepath.go +++ b/lib/fsext/filepath.go @@ -15,3 +15,31 @@ import ( func JoinFilePath(b, p string) string { return filepath.Join(b, filepath.Clean("/"+p)) } + +// Abs returns an absolute representation of path. +// +// this implementation allows k6 to handle absolute paths starting from +// the current drive on windows like `\users\noname\...`. It makes it easier +// to test and is needed for archive execution under windows (it always consider '/...' as an +// absolute path). +// +// If the path is not absolute it will be joined with root +// to turn it into an absolute path. The root path is assumed +// to be a directory. +// +// Because k6 does not interact with the OS itself, but with +// its own virtual file system, it needs to be able to resolve +// the root path of the file system. In most cases this would be +// the bundle or init environment's working directory. +func Abs(root, path string) string { + if path[0] != '/' && path[0] != '\\' && !filepath.IsAbs(path) { + path = filepath.Join(root, path) + } + path = filepath.Clean(path) + + if path[0:1] != FilePathSeparator { + path = FilePathSeparator + path + } + + return path +} diff --git a/lib/fsext/filepath_unix_test.go b/lib/fsext/filepath_unix_test.go index b6d6027d833..ff2083d17d1 100644 --- a/lib/fsext/filepath_unix_test.go +++ b/lib/fsext/filepath_unix_test.go @@ -72,3 +72,59 @@ func TestJoinFilePath(t *testing.T) { }) } } + +func TestAbs(t *testing.T) { + t.Parallel() + + type args struct { + root string + path string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "absolute path", + args: args{ + root: "/", + path: "/test", + }, + want: "/test", + }, + { + name: "relative path", + args: args{ + root: "/", + path: "test", + }, + want: "/test", + }, + { + name: "relative path with leading dot", + args: args{ + root: "/", + path: "./test", + }, + want: "/test", + }, + { + name: "relative path with leading double dot", + args: args{ + root: "/", + path: "../test", + }, + want: "/test", + }, + } + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + assert.Equal(t, tt.want, fsext.Abs(tt.args.root, tt.args.path)) + }) + } +} diff --git a/lib/fsext/filepath_windows_test.go b/lib/fsext/filepath_windows_test.go index be7697300c7..4d0c36887c3 100644 --- a/lib/fsext/filepath_windows_test.go +++ b/lib/fsext/filepath_windows_test.go @@ -64,3 +64,59 @@ func TestJoinFilePath(t *testing.T) { }) } } + +func TestAbs(t *testing.T) { + t.Parallel() + + type args struct { + root string + path string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "absolute path", + args: args{ + root: "\\", + path: "\\test", + }, + want: "\\test", + }, + { + name: "relative path", + args: args{ + root: "\\", + path: "test", + }, + want: "\\test", + }, + { + name: "relative path with leading dot", + args: args{ + root: "\\", + path: ".\\test", + }, + want: "\\test", + }, + { + name: "relative path with leading double dot", + args: args{ + root: "\\", + path: "..\\test", + }, + want: "\\test", + }, + } + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + assert.Equal(t, tt.want, fsext.Abs(tt.args.root, tt.args.path)) + }) + } +}