Skip to content

Commit

Permalink
Add a Seek method to the fs module's File type
Browse files Browse the repository at this point in the history
  • Loading branch information
oleiade committed Sep 27, 2023
1 parent bfc4019 commit c8c3626
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
51 changes: 51 additions & 0 deletions js/modules/k6/experimental/fs/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func (mi *ModuleInstance) Exports() modules.Exports {
return modules.Exports{
Named: map[string]any{
"open": mi.Open,
"SeekMode": map[string]any{
"Start": SeekModeStart,
"Current": SeekModeCurrent,
"End": SeekModeEnd,
},
},
}
}
Expand Down Expand Up @@ -241,3 +246,49 @@ func (f *File) Read(into goja.Value) *goja.Promise {

return promise
}

// Seek seeks to the given `offset` in the file, under the given `whence` mode.
//
// The returned promise resolves to the new `offset` (position) within the file, which
// is expressed in bytes from the selected start, current, or end position depending
// the provided `whence`.
func (f *File) Seek(offset goja.Value, whence goja.Value) *goja.Promise {
promise, resolve, reject := promises.New(f.vu)

if common.IsNullish(offset) {
reject(newFsError(TypeError, "seek() failed; reason: offset cannot be null or undefined"))
return promise
}

offsetInt := offset.ToInteger()
if offsetInt < 0 {
reject(newFsError(TypeError, "seek() failed; reason: offset cannot be negative"))
return promise
}

if common.IsNullish(whence) {
reject(newFsError(TypeError, "seek() failed; reason: whence cannot be null or undefined"))
return promise
}

seekMode := SeekMode(whence.ToInteger())
switch seekMode {
case SeekModeStart, SeekModeCurrent, SeekModeEnd:
// Valid modes, do nothing.
default:
reject(newFsError(TypeError, "seek() failed; reason: whence must be a SeekMode"))
return promise
}

go func() {
newOffset, err := f.file.Seek(int(offsetInt), seekMode)
if err != nil {
reject(err)
return
}

resolve(newOffset)
}()

return promise
}
81 changes: 81 additions & 0 deletions js/modules/k6/experimental/fs/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,87 @@ func TestFile(t *testing.T) {

assert.NoError(t, err)
})

t.Run("seek with invalid arguments should fail", func(t *testing.T) {
t.Parallel()

runtime, err := newConfiguredRuntime(t)
require.NoError(t, err)

testFilePath := fsext.FilePathSeparator + "bonjour.txt"
fs := newTestFs(t, func(fs afero.Fs) error {
return afero.WriteFile(fs, testFilePath, []byte("hello"), 0o644)
})
runtime.VU.InitEnvField.FileSystems["file"] = fs

_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`
const file = await fs.open(%q)
let newOffset
// null offset should fail with TypeError.
try {
newOffset = await file.seek(null)
throw "file.seek(null) promise unexpectedly resolved with result: " + newOffset
} catch (err) {
if (err.name !== 'TypeError') {
throw "file.seek(null) rejected with unexpected error: " + err
}
}
// undefined offset should fail with TypeError.
try {
newOffset = await file.seek(undefined)
throw "file.seek(undefined) promise unexpectedly promise resolved with result: " + newOffset
} catch (err) {
if (err.name !== 'TypeError') {
throw "file.seek(undefined) rejected with unexpected error: " + err
}
}
// Invalid type offset should fail with TypeError.
try {
newOffset = await file.seek('abc')
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
}
}
// Negative offset should fail with TypeError.
try {
newOffset = await file.seek(-1)
throw "file.seek(-1) promise unexpectedly resolved with result: " + newOffset
} catch (err) {
if (err.name !== 'TypeError') {
throw "file.seek(-1) rejected with unexpected error: " + err
}
}
// Invalid type whence should fail with TypeError.
try {
newOffset = await file.seek(1, 'abc')
throw "file.seek(1, 'abc') promise unexpectedly resolved with result: " + newOffset
} catch (err) {
if (err.name !== 'TypeError') {
throw "file.seek(1, 'abc') rejected with unexpected error: " + err
}
}
// Invalid whence should fail with TypeError.
try {
newOffset = await file.seek(1, -1)
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
}
}
`, testFilePath)))

assert.NoError(t, err)
})
}

func TestOpenImpl(t *testing.T) {
Expand Down

0 comments on commit c8c3626

Please sign in to comment.