Skip to content

Commit

Permalink
Expose the underlying behavior through a ReadSeekStater interface
Browse files Browse the repository at this point in the history
  • Loading branch information
oleiade committed Jun 12, 2024
1 parent 738f3bb commit 1df3e1e
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 15 deletions.
2 changes: 1 addition & 1 deletion js/modules/k6/experimental/csv/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (mi *ModuleInstance) NewParser(call goja.ConstructorCall) *goja.Object {
}

// Instantiate and configure csv reader
r := csv.NewReader(&file.Impl)
r := csv.NewReader(file.ReadSeekStater)
r.ReuseRecord = true // evaluate if this is needed, and if it leads to unforeseen issues
r.Comma = options.Delimiter // default delimiter, should be modifiable by the user

Expand Down
5 changes: 4 additions & 1 deletion js/modules/k6/experimental/fs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ type file struct {
}

// Stat returns a FileInfo describing the named file.
func (f *file) stat() *FileInfo {
func (f *file) Stat() *FileInfo {
filename := filepath.Base(f.path)
return &FileInfo{Name: filename, Size: f.size()}
}

// Ensure that `file` implements the Stater interface.
var _ Stater = (*file)(nil)

// FileInfo holds information about a file.
type FileInfo struct {
// Name holds the base name of the file.
Expand Down
31 changes: 26 additions & 5 deletions js/modules/k6/experimental/fs/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package fs
import (
"errors"
"fmt"
"io"
"reflect"

"github.com/grafana/sobek"
Expand Down Expand Up @@ -136,7 +137,7 @@ func (mi *ModuleInstance) openImpl(path string) (*File, error) {

file := &File{
Path: path,
Impl: file{
ReadSeekStater: &file{
path: path,
data: data,
},
Expand All @@ -147,6 +148,26 @@ func (mi *ModuleInstance) openImpl(path string) (*File, error) {
return file, nil
}

// Stater is an interface that provides information about a file.
//
// Although in the context of this module we have a single implementation
// of this interface, it is defined to allow exposing the `file`'s behavior
// to other module through the `ReadSeekStater` interface without having to
// leak our internal abstraction.
type Stater interface {
// Stat returns a FileInfo describing the named file.
Stat() *FileInfo
}

// ReadSeekStater is an interface that combines the io.ReadSeeker and Stater
// interfaces and ensure that structs implementing it have the necessary
// methods to interact with files.
type ReadSeekStater interface {
io.Reader
io.Seeker
Stater
}

// File represents a file and exposes methods to interact with it.
//
// It is a wrapper around the [file] struct, which is meant to be directly
Expand All @@ -162,7 +183,7 @@ type File struct {
// implementation details, but keep it public so that we can access it
// from other modules that would want to leverage its implementation of
// io.Reader and io.Seeker.
Impl file `js:"-"`
ReadSeekStater ReadSeekStater `js:"-"`

// vu holds a reference to the VU this file is associated with.
//
Expand All @@ -182,7 +203,7 @@ func (f *File) Stat() *sobek.Promise {
promise, resolve, _ := promises.New(f.vu)

go func() {
resolve(f.Impl.stat())
resolve(f.ReadSeekStater.Stat())
}()

return promise
Expand Down Expand Up @@ -227,7 +248,7 @@ func (f *File) Read(into sobek.Value) *sobek.Promise {
// occurs on the main thread, during the promise's resolution.
callback := f.vu.RegisterCallback()
go func() {
n, readErr := f.Impl.Read(buffer)
n, readErr := f.ReadSeekStater.Read(buffer)
callback(func() error {
_ = copy(intoBytes[0:n], buffer)

Expand Down Expand Up @@ -290,7 +311,7 @@ func (f *File) Seek(offset sobek.Value, whence sobek.Value) *sobek.Promise {

callback := f.vu.RegisterCallback()
go func() {
newOffset, err := f.Impl.Seek(intOffset, seekMode)
newOffset, err := f.ReadSeekStater.Seek(intOffset, seekMode)
callback(func() error {
if err != nil {
reject(err)
Expand Down
16 changes: 8 additions & 8 deletions js/modules/k6/experimental/fs/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestOpen(t *testing.T) {

_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(`
try {
const file = await fs.open('bonjour.txt')
const file = await fs.open('bonjour.txt')
throw 'unexpected promise resolution with result: ' + file;
} catch (err) {
if (err.name !== 'ForbiddenError') {
Expand Down Expand Up @@ -199,7 +199,7 @@ func TestOpen(t *testing.T) {
func TestFile(t *testing.T) {
t.Parallel()

t.Run("stat method should succeed", func(t *testing.T) {
t.Run("Stat method should succeed", func(t *testing.T) {
t.Parallel()

runtime, err := newConfiguredRuntime(t)
Expand All @@ -213,7 +213,7 @@ func TestFile(t *testing.T) {

_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`
const file = await fs.open(%q)
const info = await file.stat()
const info = await file.Stat()
if (info.name !== 'bonjour.txt') {
throw 'unexpected file name ' + info.name + '; expected \'bonjour.txt\'';
Expand Down Expand Up @@ -338,7 +338,7 @@ func TestFile(t *testing.T) {
runtime.VU.InitEnvField.FileSystems["file"] = fs

_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`
const file = await fs.open(%q);
const file = await fs.open(%q);
let bytesRead;
// No argument should fail with TypeError.
Expand Down Expand Up @@ -406,11 +406,11 @@ func TestFile(t *testing.T) {
runtime.VU.InitEnvField.FileSystems["file"] = fs

_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`
// file size is 3
// file size is 3
const file = await fs.open(%q);
// Create a buffer of size fileSize + 1
let buffer = new Uint8Array(4);
let buffer = new Uint8Array(4);
let n = await file.read(buffer)
if (n !== 3) {
throw 'expected read to return 10, got ' + n + ' instead';
Expand Down Expand Up @@ -555,7 +555,7 @@ func TestFile(t *testing.T) {
// Invalid type offset should fail with TypeError.
try {
newOffset = await file.seek('abc')
throw "file.seek('abc') promise unexpectedly resolved with result: " + newOffset
throw "file.seek('abc') promise unexpectedly resolved with result: " + newOffset
} catch (err) {
if (err.name !== 'TypeError') {
throw "file.seek('1') rejected with unexpected error: " + err
Expand Down Expand Up @@ -585,7 +585,7 @@ func TestFile(t *testing.T) {
// Invalid whence should fail with TypeError.
try {
newOffset = await file.seek(1, -1)
throw "file.seek(1, -1) promise unexpectedly resolved with result: " + newOffset
throw "file.seek(1, -1) promise unexpectedly resolved with result: " + newOffset
} catch (err) {
if (err.name !== 'TypeError') {
throw "file.seek(1, -1) rejected with unexpected error: " + err
Expand Down

0 comments on commit 1df3e1e

Please sign in to comment.