Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document k6/experimental/fs module #1419

Merged
merged 11 commits into from
Nov 29, 2023
126 changes: 63 additions & 63 deletions docs/sources/next/javascript-api/_index.md

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions docs/sources/next/javascript-api/k6-experimental/_index.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
---
title: "k6/experimental"
excerpt: "k6 experimental APIs"
title: 'k6/experimental'
excerpt: 'k6 experimental APIs'
oleiade marked this conversation as resolved.
Show resolved Hide resolved
weight: 07
---

# k6/experimental

{{< docs/shared source="k6" lookup="experimental-module.md" version="<K6_VERSION>" >}}

| Modules | Description |
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Modules | Description |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| [browser](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/browser) | Provides browser-level APIs to interact with browsers and collect frontend performance metrics as part of your k6 tests. |
| [redis](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/redis) | Functionality to interact with [Redis](https://redis.io/). |
| [timers](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/timers) | `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` |
| [tracing](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/tracing) | Support for instrumenting HTTP requests with tracing information. |
| [webcrypto](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/webcrypto) | Implements the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). |
| [websockets](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/websockets) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). |
| [grpc](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/grpc) | Extends `k6/net/grpc` with the streaming capabilities. |
| [fs](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs) | Provides a memory-efficient way to handle file interactions within your test scripts. |
oleiade marked this conversation as resolved.
Show resolved Hide resolved
67 changes: 67 additions & 0 deletions docs/sources/next/javascript-api/k6-experimental/fs/FileInfo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: 'FileInfo'
excerpt: 'FileInfo represents information about a file.'
oleiade marked this conversation as resolved.
Show resolved Hide resolved
weight: 30
---

# FileInfo

The `FileInfo` class represents information about a [file](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/file).

## Properties

| Property | Type | Description |
| :------- | :----- | :----------------------------- |
| name | string | The name of the file. |
| size | number | The size of the file in bytes. |

## Example

{{< code >}}

```javascript
import { open, SeekMode } from 'k6/experimental/fs';

let file;
(async function () {
file = await open('bonjour.txt');
})();

export default async function () {
// About information about the file
oleiade marked this conversation as resolved.
Show resolved Hide resolved
const fileinfo = await file.stat();
if (fileinfo.name != 'bonjour.txt') {
throw new Error('Unexpected file name');
}

const buffer = new Uint8Array(4);

let totalBytesRead = 0;
while (true) {
// Read into the buffer
const bytesRead = await file.read(buffer);
if (bytesRead == null) {
// EOF
break;
}

// Do something useful with the content of the buffer
totalBytesRead += bytesRead;

// If bytesRead is less than the buffer size, we've read the whole file
if (bytesRead < buffer.byteLength) {
break;
}
}

// Check that we read the expected number of bytes
if (totalBytesRead != fileinfo.size) {
throw new Error('Unexpected number of bytes read');
}

// Seek back to the beginning of the file
await file.seek(0, SeekMode.Start);
oleiade marked this conversation as resolved.
Show resolved Hide resolved
}
```

{{< /code >}}
43 changes: 43 additions & 0 deletions docs/sources/next/javascript-api/k6-experimental/fs/SeekMode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: 'SeekMode'
excerpt: 'SeekMode is used to specify the position from which to seek in a file.'
oleiade marked this conversation as resolved.
Show resolved Hide resolved
weight: 40
---

# SeekMode

The `SeekMode` enum is used to specify the position from which to [seek](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/file/seek) in a file.
oleiade marked this conversation as resolved.
Show resolved Hide resolved

## Members

| Member | Value | Description |
| :------ | :---- | :------------------------------------------ |
| Start | 0 | Seek from the start of the file. |
| Current | 1 | Seek from the current position in the file. |
| End | 2 | Seek from the end of the file. |

## Example

{{< code >}}

```javascript
import { open, SeekMode } from 'k6/experimental/fs';

let file;
(async function () {
file = await open('bonjour.txt');
})();

export default async function () {
// Seek 6 bytes from the start of the file
await file.seek(6, SeekMode.Start);

// Seek 2 more bytes from the current position
await file.seek(2, SeekMode.Current);

// Seek backwards 2 bytes from the end of the file
await file.seek(-2, SeekMode.End);
}
```

{{< /code >}}
84 changes: 84 additions & 0 deletions docs/sources/next/javascript-api/k6-experimental/fs/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: 'fs'
excerpt: 'k6 fs experimental API'
oleiade marked this conversation as resolved.
Show resolved Hide resolved
weight: 10
---

# fs

{{< docs/shared source="k6" lookup="experimental-module.md" version="<K6_VERSION>" >}}

The k6 filesystem experimental module provides a memory-efficient way to handle file interactions within your test scripts. It currently offers support for opening files, reading their content, and seeking through their content, and retrieving metadata about them.
oleiade marked this conversation as resolved.
Show resolved Hide resolved

### Memory efficiency

One of the key advantages of the filesystem module is its memory efficiency. Unlike the traditional [open]() function, which loads a file multiple times into memory, the filesystem module reduces memory usage by loading the file as little possible, and sharing the same memory space between all VUs. This approach signally reduces the memory footprint of your test script, and lets you load and process large files without running out of memory.
oleiade marked this conversation as resolved.
Show resolved Hide resolved

### Notes on usage

An important consideration when using the filesystem module is its handling of external file modifications. Once a file is loaded in k6, it behaves like a "view" over the content of the file. This means that if the underlying file is modified externally during a test, those changes won't be reflected in the loaded [File]() instance.
oleiade marked this conversation as resolved.
Show resolved Hide resolved

## API Overview

The module exports functions and objects to interact with the file system:

| Function/Object | Description |
| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [open](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/open) | Opens a file and returns a promise resolving to a `File` instance. |
| [File](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/file) | Represents a file with methods for reading, seeking, and obtaining file stats. |
| [SeekMode](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/seekmode) | Enum for specifying the reference point for seek operations. Includes `Start`, `Current`, and `End`. |

## Example

{{< code >}}

```javascript
import { open, SeekMode } from 'k6/experimental/fs';

// k6 doesn't support async in the init context. We use a top-level async function for `await`.
//
// Each Virtual User gets its own `file` copy.
// So, operations like `seek` or `read` won't impact other VUs.
let file;
(async function () {
file = await open('bonjour.txt');
})();

export default async function () {
// About information about the file
const fileinfo = await file.stat();
if (fileinfo.name != 'bonjour.txt') {
throw new Error('Unexpected file name');
}

const buffer = new Uint8Array(4);

let totalBytesRead = 0;
while (true) {
// Read into the buffer
const bytesRead = await file.read(buffer);
if (bytesRead == null) {
// EOF
break;
}

// Do something useful with the content of the buffer
totalBytesRead += bytesRead;

// If bytesRead is less than the buffer size, we've read the whole file
if (bytesRead < buffer.byteLength) {
break;
}
}

// Check that we read the expected number of bytes
if (totalBytesRead != fileinfo.size) {
throw new Error('Unexpected number of bytes read');
}

// Seek back to the beginning of the file
await file.seek(0, SeekMode.Start);
}
```

{{< /code >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: 'File'
excerpt: 'File represents a file with methods for reading, seeking, and obtaining file stats.'
oleiade marked this conversation as resolved.
Show resolved Hide resolved
weight: 10
weight: 10
oleiade marked this conversation as resolved.
Show resolved Hide resolved
---

# File

The `File` class represents a file with methods for reading, seeking, and obtaining file stats. It's returned by the [open](link-to-open-doc) function.
oleiade marked this conversation as resolved.
Show resolved Hide resolved

## Properties

| Property | Type | Description |
| :------- | :----- | :----------------------------- |
| path | string | The absolute path to the file. |

## Methods

| Method | Description |
| :------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- |
| [read](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/file/read) | Reads up to `buffer.byteLength` bytes from the file into the passed `buffer`. Returns a promise resolving to the number of bytes read. |
| [seek](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/file/seek) | Sets the file position indicator for the file to the passed `offset` bytes. Returns a promise resolving to the new offset. |
| [stat](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-experimental/fs/file/stat) | Returns a promise resolving to a [FileInfo](link-to-fileinfo-doc) object with information about the file. |
oleiade marked this conversation as resolved.
Show resolved Hide resolved

## Example

{{< code >}}

```javascript
import { open, SeekMode } from 'k6/experimental/fs';

let file;
(async function () {
file = await open('bonjour.txt');
})();

export default async function () {
// About information about the file
const fileinfo = await file.stat();
if (fileinfo.name != 'bonjour.txt') {
throw new Error('Unexpected file name');
}

const buffer = new Uint8Array(4);

let totalBytesRead = 0;
while (true) {
// Read into the buffer
const bytesRead = await file.read(buffer);
if (bytesRead == null) {
// EOF
break;
}

// Do something useful with the content of the buffer
totalBytesRead += bytesRead;

// If bytesRead is less than the buffer size, we've read the whole file
if (bytesRead < buffer.byteLength) {
break;
}
}

// Check that we read the expected number of bytes
if (totalBytesRead != fileinfo.size) {
throw new Error('Unexpected number of bytes read');
}

// Seek back to the beginning of the file
await file.seek(0, SeekMode.Start);
}
```

{{< /code >}}
oleiade marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: 'read'
excerpt: 'the read method is used to read a chunk of the file.'
oleiade marked this conversation as resolved.
Show resolved Hide resolved
weight: 20
---

# read

The `read` method is used to read a chunk of the file into an [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) buffer.

It resolves to either the number of bytes read during the operation, or `null` if there was nothing more to read.

## Parameters

| Parameter | Type | Description |
| :-------- | :-------------------------------------------------------------------------------------------------------- | :-------------------------------- |
| buffer | [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) | The buffer to read the data into. |

## Returns

A [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) resolving to the number of bytes read or `null` if the end of the file has been reached.

## Example

{{< code >}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a comment, the {{< code >}} shortcode main purpose is to support multiple code snippets (how to do X in JavaScript, and in Ruby, for example). It still works if you have a single code snippet inside of it, but we don't necessarily need it here. 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's good to know! I think it still makes sense to have it even with a single example? Makes it more explicit too as it will display "Javascript" above the code right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still get the "JavaScript" title even without the code shortcode. (I wasn't sure about it so I tested it out 😆). The only UI difference seems to be the underline in the shortcode version.

Screenshot 2023-11-28 at 2 29 02 PM


```javascript
import { open, SeekMode } from 'k6/experimental/fs';

let file;
(async function () {
file = await open('bonjour.txt');
})();

export default async function () {
// About information about the file
const fileinfo = await file.stat();
if (fileinfo.name != 'bonjour.txt') {
throw new Error('Unexpected file name');
}

const buffer = new Uint8Array(4);
oleiade marked this conversation as resolved.
Show resolved Hide resolved

let totalBytesRead = 0;
while (true) {
// Read into the buffer
const bytesRead = await file.read(buffer);
if (bytesRead == null) {
// EOF
break;
}

// Do something useful with the content of the buffer
totalBytesRead += bytesRead;

// If bytesRead is less than the buffer size, we've read the whole file
if (bytesRead < buffer.byteLength) {
break;
}
}

// Check that we read the expected number of bytes
if (totalBytesRead != fileinfo.size) {
throw new Error('Unexpected number of bytes read');
}

oleiade marked this conversation as resolved.
Show resolved Hide resolved
// Seek back to the beginning of the file
await file.seek(0, SeekMode.Start);
oleiade marked this conversation as resolved.
Show resolved Hide resolved
}
oleiade marked this conversation as resolved.
Show resolved Hide resolved
```

{{< /code >}}
Loading
Loading