diff --git a/gatsby-node.js b/gatsby-node.js index 1d304555d7..a8b7e2b10d 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -176,11 +176,19 @@ const getPageVersions = ( const topLevelLinks = [ { label: 'guides', - to: 'https://grafana.com/docs/k6/latest/', + to: '/', }, { label: 'JAVASCRIPT API', - to: 'https://grafana.com/docs/k6/latest/javascript-api/', + to: '/javascript-api/', + submenu: [ + { label: 'k6 API', to: `/javascript-api/` }, + { + label: 'xk6-disruptor', + to: `/javascript-api/xk6-disruptor/`, + }, + { label: 'jslib', to: `/javascript-api/jslib/` }, + ], }, { label: 'Cloud Docs', @@ -195,15 +203,15 @@ const topLevelLinks = [ }, { label: 'Extensions', - to: 'https://grafana.com/docs/k6/latest/extensions/', + to: '/extensions/', }, { label: 'Integrations', - to: 'https://grafana.com/docs/k6/latest/misc/integrations/', + to: '/integrations/', }, { label: 'examples', - to: 'https://grafana.com/docs/k6/latest/examples/', + to: '/examples/', }, ]; @@ -1171,10 +1179,7 @@ async function createDocPages({ reporter, }), ) - .map((pageProps) => - // console.log(pageProps.path); - actions.createPage(pageProps), - ); + .map((pageProps) => actions.createPage(pageProps)); } const createRedirects = ({ actions }) => { @@ -2094,7 +2099,6 @@ exports.onCreateNode = ({ node, actions }) => { // Adding default values for some fields and moving them under node.fields // because that how createNodeField works if (node.frontmatter) { - // console.log('node slug: ' , node.frontmatter.slug); createNodeField({ node, name: 'redirect', diff --git a/src/components/blocks/footer/footer.view.js b/src/components/blocks/footer/footer.view.js index f474ead8fe..e60e7231a1 100644 --- a/src/components/blocks/footer/footer.view.js +++ b/src/components/blocks/footer/footer.view.js @@ -1,199 +1,353 @@ +import SubscribeForm from 'components/shared/subscribe-form'; import { Link } from 'gatsby'; -import React from 'react'; +import React, { useState, useEffect } from 'react'; import Logo from 'svg/logo-with-grafana-labs.inline.svg'; -import { blog, main } from 'utils/urls'; +import { blog, main, docs } from 'utils/urls'; import styles from './footer.module.scss'; +import GithubLogo from './svg/github.inline.svg'; import HeartIcon from './svg/heart-purple.inline.svg'; +import LinkedinLogo from './svg/linkedin.inline.svg'; +import MeetupLogo from './svg/meetup.inline.svg'; +import SlackLogo from './svg/slack.inline.svg'; +import TwitterLogo from './svg/twitter.inline.svg'; +import YoutubeLogo from './svg/youtube.inline.svg'; import './footer.scss'; +const Badge = ({ children }) => ( + {children} +); + const Heart = () => ( ); -export const Footer = () => ( - + ); +}; diff --git a/src/components/pages/doc-welcome/outdated-blockquote/index.js b/src/components/pages/doc-welcome/outdated-blockquote/index.js deleted file mode 100644 index c156aec5c0..0000000000 --- a/src/components/pages/doc-welcome/outdated-blockquote/index.js +++ /dev/null @@ -1 +0,0 @@ -export { OutdatedBlockquote } from './outdated-blockquote.view'; diff --git a/src/components/pages/doc-welcome/outdated-blockquote/outdated-blockquote.view.js b/src/components/pages/doc-welcome/outdated-blockquote/outdated-blockquote.view.js deleted file mode 100644 index 7c559927e9..0000000000 --- a/src/components/pages/doc-welcome/outdated-blockquote/outdated-blockquote.view.js +++ /dev/null @@ -1,27 +0,0 @@ -import Blockquote from 'components/shared/blockquote'; -import React from 'react'; - -export const OutdatedBlockquote = () => ( -
-
-

- We've migrated the k6 documentation to Grafana!{' '} - - Click here - {' '} - to view the latest version of the k6 documentation. -
-
- This page is still available for users to be able to view the{' '} - - k6 Cloud documentation - - , and will be removed at a later date. -

-
-
-
-); diff --git a/src/components/pages/doc-welcome/use-cases/use-cases.view.js b/src/components/pages/doc-welcome/use-cases/use-cases.view.js index 639f46a82b..a7f8e3d2c1 100644 --- a/src/components/pages/doc-welcome/use-cases/use-cases.view.js +++ b/src/components/pages/doc-welcome/use-cases/use-cases.view.js @@ -1,5 +1,6 @@ import { Heading } from 'components/shared/heading'; import { useI18n } from 'contexts/i18n-provider'; +import { useLocale } from 'contexts/locale-provider'; import { Link } from 'gatsby'; import React from 'react'; @@ -7,6 +8,7 @@ import styles from './use-cases.module.scss'; export const UseCases = () => { const { t } = useI18n(); + const { urlLocale } = useLocale(); return (
@@ -24,7 +26,9 @@ export const UseCases = () => { spike @@ -33,7 +37,9 @@ export const UseCases = () => { stress @@ -42,7 +48,9 @@ export const UseCases = () => { soak tests @@ -57,10 +65,7 @@ export const UseCases = () => {

{t('welcome.use-cases.browser-testing.pre-description')} - + k6 browser {t('welcome.use-cases.browser-testing.description')} @@ -71,15 +76,8 @@ export const UseCases = () => { {t('welcome.use-cases.chaos-testing.title')}

- You can use k6 to simulate traffic as part of your chaos - experiments, trigger them from your k6 tests or inject different - types of faults in Kubernetes with{' '} - + {t('welcome.use-cases.chaos-testing.description')} + xk6-disruptor . @@ -89,22 +87,7 @@ export const UseCases = () => { {t('welcome.use-cases.performance-monitoring.title')} -

- With k6, you can automate and schedule to trigger tests very - frequently with a small load to continuously validate the - performance and availability of your production environment. You can - also use{' '} - - Grafana Cloud Synthetic Monitoring - {' '} - for a managed solution built specifically for synthetic monitoring - that supports k6 test scripts. -

+

{t('welcome.use-cases.performance-monitoring.description')}

diff --git a/src/data/markdown/docs/02 javascript api/01 Init context.md b/src/data/markdown/docs/02 javascript api/01 Init context.md index a9be961100..c5b5f2572d 100644 --- a/src/data/markdown/docs/02 javascript api/01 Init context.md +++ b/src/data/markdown/docs/02 javascript api/01 Init context.md @@ -2,7 +2,12 @@ title: "Init context" excerpt: 'The init context (aka "init code") is code in the global context that has access to a few functions not accessible during main script execution.' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/init-context/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/init-context/ --- Before the k6 starts the test logic, code in the _init context_ prepares the script. +A few functions are available only in init context. +For details about the runtime, refer to the [Test lifecycle](/using-k6/test-lifecycle). + +| Function | Description | +| ----------------------------------------------------------------------------------- | --------------------- | +| [open( filePath, [mode] )](/javascript-api/init-context/open) | Opens a file and reads all the contents into memory. | diff --git a/src/data/markdown/docs/02 javascript api/01 Init context/open.md b/src/data/markdown/docs/02 javascript api/01 Init context/open.md new file mode 100644 index 0000000000..77b90a61a4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/01 Init context/open.md @@ -0,0 +1,113 @@ +--- +head_title: 'JavaScript API: open' +title: 'open( filePath, [mode] )' +description: 'Opens a file and reads all the contents into memory.' +excerpt: 'Opens a file and reads all the contents into memory.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/init-context/open/ +--- + +Opens a file, reading all its contents into memory for use in the script. + +> #### Use [SharedArray](/javascript-api/k6-data/sharedarray/) for CSV and JSON files +> `open()` often consumes a large amount of memory because every VU keeps a separate copy of the file in memory. +> To reduce the memory consumption, we strongly advise the usage of [SharedArray](/javascript-api/k6-data/sharedarray/) for CSV, JSON and other files intended for script parametrization. + +
+ +This function can only be called from the init context (aka _init code_), code in the global context that is, outside of the main export default function { ... }. + +By restricting it to the init context, we can easily determine what local files are needed to run the test and thus what we need to bundle up when distributing the test to multiple nodes in a clustered/distributed test. + +See the example further down on this page. For a more in-depth description, see [Test lifecycle](/using-k6/test-lifecycle). + +
+ +| Parameter | Type | Description | +| --------- | ------ | ------------------ | +| filePath | string | The path to the file, absolute or relative, that will be read into memory. The file will only be loaded once, even when running with several VUs. | +| mode | string | By default, the contents of the file are read as text, but if you specify `b`, the file will be read as binary data instead. | + +### Returns + +| Type | Description | +| ---- | ----------- | +| string / ArrayBuffer | The contents of the file, returned as string or ArrayBuffer (if `b` was specified as the mode). | + + + + +```json +[ + { + "username": "user1", + "password": "password1" + }, + { + "username": "user2", + "password": "password2" + }, + { + "username": "user3", + "password": "password3" + } +] +``` + + + + + +```javascript +import { SharedArray } from 'k6/data'; +import { sleep } from 'k6'; + +const data = new SharedArray('users', function () { + // here you can open files, and then do additional processing or generate the array with data dynamically + const f = JSON.parse(open('./users.json')); + return f; // f must be an array[] +}); + +export default () => { + const randomUser = data[Math.floor(Math.random() * data.length)]; + console.log(`${randomUser.username}, ${randomUser.password}`); + sleep(3); +}; +``` + + + + + +```javascript +import { sleep } from 'k6'; + +const users = JSON.parse(open('./users.json')); // consider using SharedArray for large files + +export default function () { + const user = users[__VU - 1]; + console.log(`${user.username}, ${user.password}`); + sleep(3); +} +``` + + + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +const binFile = open('/path/to/file.bin', 'b'); + +export default function () { + const data = { + field: 'this is a standard form field', + file: http.file(binFile, 'test.bin'), + }; + const res = http.post('https://example.com/upload', data); + sleep(3); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/02 k6.md b/src/data/markdown/docs/02 javascript api/02 k6.md index f0143895dc..dbd889ce7d 100644 --- a/src/data/markdown/docs/02 javascript api/02 k6.md +++ b/src/data/markdown/docs/02 javascript api/02 k6.md @@ -2,7 +2,14 @@ title: 'k6' excerpt: 'The k6 module contains k6-specific functionality.' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6/ --- The k6 module contains k6-specific functionality. + +| Function | Description | +| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| [check(val, sets, [tags])](/javascript-api/k6/check) | Runs one or more checks on a value and generates a pass/fail result but does not throw errors or otherwise interrupt execution upon failure. | +| [fail([err])](/javascript-api/k6/fail) | Throws an error, failing and aborting the current VU script iteration immediately. | +| [group(name, fn)](/javascript-api/k6/group) | Runs code inside a group. Used to organize results in a test. | +| [randomSeed(int)](/javascript-api/k6/randomseed) | Set seed to get a reproducible pseudo-random number using `Math.random`. | +| [sleep(t)](/javascript-api/k6/sleep) | Suspends VU execution for the specified duration. | diff --git a/src/data/markdown/docs/02 javascript api/02 k6/check- val- sets- -tags- -.md b/src/data/markdown/docs/02 javascript api/02 k6/check- val- sets- -tags- -.md new file mode 100644 index 0000000000..cf7c89185f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/02 k6/check- val- sets- -tags- -.md @@ -0,0 +1,73 @@ +--- +title: 'check( val, sets, [tags] )' +description: 'Runs one or more checks on a value and generates a pass/fail result but does not throw errors or otherwise interrupt execution upon failure.' +excerpt: 'Runs one or more checks on a value and generates a pass/fail result but does not throw errors or otherwise interrupt execution upon failure.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6/check/ +--- + +Run checks on a value. A check is a test condition that can give a truthy or +falsy result. The `sets` parameter contains one or more checks, and the `check()` +function will return `false` if any of them fail. + +Note that checks are not _asserts_ in their traditional sense - a failed assertion +will throw an error, while a check will always return with a pass or a failure. +Failure conditions can then instead be controlled by thresholds, for more power and flexibility. + +| Parameter | Type | Description | +| --------------- | ------ | ---------------------------------------- | +| val | any | Value to test. | +| sets | object | Tests (checks) to run on the value. | +| tags (optional) | object | Extra tags to attach to metrics emitted. | + +### Returns + +| Type | Description | +| ------- | ------------------------------------------------------- | +| boolean | `true` if all checks have succeeded, `false` otherwise. | + +### Examples + +Using `check()` to verify that an HTTP response code was 200: + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const res = http.get('https://httpbin.test.k6.io'); + check(res, { + 'response code was 200': (res) => res.status == 200, + }); +} +``` + + + +Using `check()` with a custom tag to verify that an HTTP response code was 200 and that body was 1234 bytes. The `checkOutput` can be used for any condition in your script logic: + + + +```javascript +import http from 'k6/http'; +import { check, fail } from 'k6'; + +export default function () { + const res = http.get('https://httpbin.test.k6.io'); + const checkOutput = check( + res, + { + 'response code was 200': (res) => res.status == 200, + 'body size was 1234 bytes': (res) => res.body.length == 1234, + }, + { myTag: "I'm a tag" } + ); + + if (!checkOutput) { + fail('unexpected response'); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/02 k6/fail- -err- -.md b/src/data/markdown/docs/02 javascript api/02 k6/fail- -err- -.md new file mode 100644 index 0000000000..6e555e608c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/02 k6/fail- -err- -.md @@ -0,0 +1,42 @@ +--- +title: 'fail( [err] )' +description: 'Throws an error, failing and aborting the current VU script iteration immediately.' +excerpt: 'Throws an error, failing and aborting the current VU script iteration immediately.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6/fail/ +--- + +Immediately throw an error, aborting the current iteration. + +`fail()` does not abort the test, nor does it make the test exit with non-0 status. +If you are looking to fail the test by halting the execution, use [test.abort()](/javascript-api/k6-execution/#test) instead + +`fail()` is a simple convenience wrapper on top of JavaScript's `throw()`, +because the latter cannot be used as `[expr] || throw`, which is a convenient way to write k6 test code. + +| Parameter | Type | Description | +| -------------- | ------ | ------------------------------------------ | +| err (optional) | string | Error message that gets printed to stderr. | + +### Example + +Aborting the current script iteration if a check fails: + + + +```javascript +import http from 'k6/http'; +import { check, fail } from 'k6'; + +export default function () { + const res = http.get('https://k6.io'); + if ( + !check(res, { + 'status code MUST be 200': (res) => res.status == 200, + }) + ) { + fail('status code was *not* 200'); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/02 k6/group- name- fn -.md b/src/data/markdown/docs/02 javascript api/02 k6/group- name- fn -.md new file mode 100644 index 0000000000..b814c23077 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/02 k6/group- name- fn -.md @@ -0,0 +1,66 @@ +--- +title: 'group( name, fn )' +description: 'Runs code inside a group. Used to organize results in a test.' +excerpt: 'Runs code inside a group. Used to organize results in a test.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6/group/ +--- + +Run code inside a group. Groups are used to organize results in a test. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------------------------ | +| name | string | Name of the group. | +| fn | function | Group body - code to be executed in the group context. | + +### Returns + +| Type | Description | +| ---- | ------------------------- | +| any | The return value of _fn_. | + +
+ +Avoid using `group` with async functions or asynchronous code. +If you do, k6 might apply tags in a way that is unreliable or unintuitive. + +If you start promise chains or even use `await` within `group`, some code within the group will be waited for and tagged with the proper `group` tag, but others won't be. + +To avoid confusion, `async` functions are forbidden as `group()` arguments. This still lets users make and chain promises within a group, but doing so is unsupported and not recommended. + +For more information, refer to [k6 #2728](https://github.com/grafana/k6/issues/2728), which tracks possible solutions and provides detailed explanations. + +
+ +### Example + + + +```javascript +import { group } from 'k6'; + +export default function () { + group('visit product listing page', function () { + // ... + }); + group('add several products to the shopping cart', function () { + // ... + }); + group('visit login page', function () { + // ... + }); + group('authenticate', function () { + // ... + }); + group('checkout process', function () { + // ... + }); +} +``` + + + +The above code will present the results separately depending on the group execution. + +Learn more on [Groups and Tags](/using-k6/tags-and-groups). + + diff --git a/src/data/markdown/docs/02 javascript api/02 k6/images/groups.png b/src/data/markdown/docs/02 javascript api/02 k6/images/groups.png new file mode 100644 index 0000000000..4135d30379 Binary files /dev/null and b/src/data/markdown/docs/02 javascript api/02 k6/images/groups.png differ diff --git a/src/data/markdown/docs/02 javascript api/02 k6/random-seed.md b/src/data/markdown/docs/02 javascript api/02 k6/random-seed.md new file mode 100644 index 0000000000..3906e88377 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/02 k6/random-seed.md @@ -0,0 +1,35 @@ +--- +title: 'randomSeed( int )' +description: 'Set seed to get a reproducible pseudo-random number using `Math.random`.' +excerpt: 'Set seed to get a reproducible pseudo-random number using `Math.random`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6/random-seed/ +--- + +Set seed to get a reproducible pseudo-random number using `Math.random`. + +| Parameter | Type | Description | +| --------- | ------- | --------------- | +| int | integer | The seed value. | + +### Example + +Use `randomSeed` to get the same random number in all the iterations. + + + +```javascript +import { randomSeed } from 'k6'; + +export const options = { + vus: 10, + duration: '5s', +}; + +export default function () { + randomSeed(123456789); + const rnd = Math.random(); + console.log(rnd); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/02 k6/sleep- t -.md b/src/data/markdown/docs/02 javascript api/02 k6/sleep- t -.md new file mode 100644 index 0000000000..40826fdfc9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/02 k6/sleep- t -.md @@ -0,0 +1,49 @@ +--- +title: 'sleep( t )' +description: 'Suspends VU execution for the specified duration.' +excerpt: 'Suspends VU execution for the specified duration.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6/sleep/ +--- + +Suspend VU execution for the specified duration. + +| Parameter | Type | Description | +| --------- | ------ | --------------------- | +| t | number | Duration, in seconds. | + +### Examples + +Fetching two different pages with a 0-30 second random sleep in between: + + + +```javascript +import { sleep } from 'k6'; +import http from 'k6/http'; + +export default function () { + http.get('https://k6.io'); + sleep(Math.random() * 30); + http.get('https://k6.io/features'); +} +``` + + + +Using the [k6-utils](https://k6.io/docs/javascript-api/jslib/utils) library to specify a range between a minimum and maximum: + + + +```javascript +import { sleep } from 'k6'; +import http from 'k6/http'; +import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +export default function () { + http.get('https://k6.io'); + sleep(randomIntBetween(20, 30)); + http.get('https://k6.io/features'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto.md index 1fd0d5bdf2..3194a13f93 100644 --- a/src/data/markdown/docs/02 javascript api/03 k6-crypto.md +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto.md @@ -2,6 +2,29 @@ title: "k6/crypto" excerpt: "The k6/crypto module provides common hashing functionality available in the GoLang crypto." canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/ --- + + +The k6/crypto `module` provides common hashing functionality available in the GoLang [crypto](https://golang.org/pkg/crypto/) package. + +| Function | Description | +| -------- | ----------- | +| [createHash(algorithm)](/javascript-api/k6-crypto/createhash) | Create a Hasher object, allowing the user to add data to hash multiple times, and extract hash digests along the way. | +| [createHMAC(algorithm, secret)](/javascript-api/k6-crypto/createhmac) | Create an HMAC hashing object, allowing the user to add data to hash multiple times, and extract hash digests along the way. | +| [hmac(algorithm, secret, data, outputEncoding)](/javascript-api/k6-crypto/hmac) | Use HMAC to sign an input string. | +| [md4(input, outputEncoding)](/javascript-api/k6-crypto/md4) | Use MD4 to hash an input string. | +| [md5(input, outputEncoding)](/javascript-api/k6-crypto/md5) | Use MD5 to hash an input string. | +| [randomBytes(int)](/javascript-api/k6-crypto/randombytes) | Return an array with a number of cryptographically random bytes. | +| [ripemd160(input, outputEncoding)](/javascript-api/k6-crypto/ripemd160) | Use RIPEMD-160 to hash an input string. | +| [sha1(input, outputEncoding)](/javascript-api/k6-crypto/sha1) | Use SHA-1 to hash an input string. | +| [sha256(input, outputEncoding)](/javascript-api/k6-crypto/sha256) | Use SHA-256 to hash an input string. | +| [sha384(input, outputEncoding)](/javascript-api/k6-crypto/sha384) | Use SHA-384 to hash an input string. | +| [sha512(input, outputEncoding)](/javascript-api/k6-crypto/sha512) | Use SHA-512 to hash an input string. | +| [sha512_224(input, outputEncoding)](/javascript-api/k6-crypto/sha512_224) | Use SHA-512/224 to hash an input string. | +| [sha512_256(input, outputEncoding)](/javascript-api/k6-crypto/sha512_256) | Use SHA-512/256 to hash an input string. | + + +| Class | Description | +| -------- | ----------- | +| [Hasher](/javascript-api/k6-crypto/hasher) | Object returned by [crypto.createHash()](/javascript-api/k6-crypto/createhash). It allows adding more data to be hashed and to extract digests along the way. | diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/01-createHash- algorithm -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/01-createHash- algorithm -.md new file mode 100644 index 0000000000..efb2996c4c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/01-createHash- algorithm -.md @@ -0,0 +1,45 @@ +--- +title: 'createHash( algorithm )' +description: 'Create a Hasher object, allowing the user to add data to hash multiple times, and extract hash digests along the way.' +excerpt: 'Create a Hasher object, allowing the user to add data to hash multiple times, and extract hash digests along the way.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/createhash/ +--- + + + +Creates a hashing object that can then be fed with data repeatedly, and from which you can extract a hash digest whenever you want. + +| Parameter | Type | Description | +| --------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| algorithm | string | The name of the hashing algorithm you want to use. Can be any one of "md4", "md5", "sha1", "sha256", "sha384", "sha512", "sha512_224", "sha512_256", "ripemd160". | + +### Returns + +| Type | Description | +| ------ | ---------------------------------------------------- | +| object | A [Hasher](/javascript-api/k6-crypto/hasher) object. | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + console.log(crypto.sha256('hello world!', 'hex')); + const hasher = crypto.createHash('sha256'); + hasher.update('hello '); + hasher.update('world!'); + console.log(hasher.digest('hex')); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 +INFO[0000] 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/02-createHMAC- algorithm- secret -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/02-createHMAC- algorithm- secret -.md new file mode 100644 index 0000000000..8fd274a153 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/02-createHMAC- algorithm- secret -.md @@ -0,0 +1,46 @@ +--- +title: 'createHMAC( algorithm, secret )' +description: 'Create an HMAC hashing object, allowing the user to add data to hash multiple times, and extract hash digests along the way.' +excerpt: 'Create an HMAC hashing object, allowing the user to add data to hash multiple times, and extract hash digests along the way.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/createhmac/ +--- + + + +Creates a HMAC hashing object that can then be fed with data repeatedly, and from which you can extract a signed hash digest whenever you want. + +| Parameter | Type | Description | +| --------- | :----: | :---------------------------------------------------------------------------------------------------------------------------------- | +| algorithm | string | The hashing algorithm to use. One of `md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `sha512_224`, `sha512_256` or `ripemd160`. | +| secret | string / ArrayBuffer | A shared secret used to sign the data. | + +### Returns + +| Type | Description | +| ------ | :--------------------------------------------------- | +| object | A [Hasher](/javascript-api/k6-crypto/hasher) object. | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + console.log(crypto.hmac('sha256', 'a secret', 'my data', 'hex')); + const hasher = crypto.createHMAC('sha256', 'a secret'); + hasher.update('my '); + hasher.update('data'); + console.log(hasher.digest('hex')); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] 82f669c8fde13aef6d6977257588dc4953dfac505428f8fd6b52e19cd96d7ea5 +INFO[0000] 82f669c8fde13aef6d6977257588dc4953dfac505428f8fd6b52e19cd96d7ea5 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/03-hmac- algorithm- secret- data- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/03-hmac- algorithm- secret- data- outputEncoding -.md new file mode 100644 index 0000000000..ca79dd0a1f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/03-hmac- algorithm- secret- data- outputEncoding -.md @@ -0,0 +1,53 @@ +--- +title: 'hmac( algorithm, secret, data, outputEncoding )' +description: 'Use HMAC to sign input data.' +excerpt: 'Use HMAC to sign input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/hmac/ +--- + + + +Use [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code) to sign a piece of data using a shared secret. + +| Parameter | Type | Description | +| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- | +| algorithm | string | The hashing algorithm to use. One of `md4`, `md5`, `sha1`, `sha256`, `sha384`, `sha512`, `sha512_224`, `sha512_256` or `ripemd160`. | +| secret | string / ArrayBuffer | A shared secret used to sign the data. | +| data | string / ArrayBuffer | The data to sign. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.hmac('sha256', 'mysecret', 'hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.hmac('sha256', 'mysecret', new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + + + +```bash +INFO[0000] 893a72d8cab129e5ba85aea4599fd53f59bfe652cff4098a3780313228d8c20f +INFO[0000] 893a72d8cab129e5ba85aea4599fd53f59bfe652cff4098a3780313228d8c20f +``` + + diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/04-md4- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/04-md4- input- outputEncoding -.md new file mode 100644 index 0000000000..ab1fe21e9f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/04-md4- input- outputEncoding -.md @@ -0,0 +1,46 @@ +--- +title: 'md4( input, outputEncoding )' +description: 'Use MD4 to hash input data.' +excerpt: 'Use MD4 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/md4/ +--- + + + +Use [md4](https://pkg.go.dev/golang.org/x/crypto/md4) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.md4('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.md4(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] 3363b72840acd5f49f922fef598ee85d +INFO[0000] 3363b72840acd5f49f922fef598ee85d +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/05-md5- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/05-md5- input- outputEncoding -.md new file mode 100644 index 0000000000..fa9d188630 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/05-md5- input- outputEncoding -.md @@ -0,0 +1,46 @@ +--- +title: 'md5( input, outputEncoding )' +description: 'Use MD5 to hash input data.' +excerpt: 'Use MD5 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/md5/ +--- + + + +Use [md5](https://golang.org/pkg/crypto/md5/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.md5('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.md5(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] fc3ff98e8c6a0d3087d515c0473f8677 +INFO[0000] fc3ff98e8c6a0d3087d515c0473f8677 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/06-randomBytes- int -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/06-randomBytes- int -.md new file mode 100644 index 0000000000..d333b1c2b3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/06-randomBytes- int -.md @@ -0,0 +1,36 @@ +--- +title: 'randomBytes( int )' +description: 'randomBytes.' +excerpt: 'randomBytes.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/randombytes/ +--- + + + +Return an ArrayBuffer object with a number of cryptographically random bytes. It will either return exactly the amount of bytes requested or will throw an exception if something went wrong. + +| Parameter | Type | Description | +| --------- | ------- | --------------------------------------- | +| int | integer | The length of the returned ArrayBuffer. | + +### Returns + +| Type | Description | +| ----------- | --------------------------------------------------- | +| ArrayBuffer | An ArrayBuffer with cryptographically random bytes. | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + const bytes = crypto.randomBytes(42); + const view = new Uint8Array(bytes); + console.log(view); // 156,71,245,191,56,... +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/07-ripemd160- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/07-ripemd160- input- outputEncoding -.md new file mode 100644 index 0000000000..aacd651420 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/07-ripemd160- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'ripemd160( input, outputEncoding )' +description: 'Use RIPEMD-160 to hash input data.' +excerpt: 'Use RIPEMD-160 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/ripemd160/ +--- + + + +Use [ripemd160](https://pkg.go.dev/golang.org/x/crypto/ripemd160) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.ripemd160('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.ripemd160(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] dffd03137b3a333d5754813399a5f437acd694e5 +INFO[0000] dffd03137b3a333d5754813399a5f437acd694e5 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/08-sha1- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/08-sha1- input- outputEncoding -.md new file mode 100644 index 0000000000..5aea396f97 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/08-sha1- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'sha1( input, outputEncoding )' +description: 'Use SHA-1 to hash input data.' +excerpt: 'Use SHA-1 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/sha1/ +--- + + + +Use [sha1](https://golang.org/pkg/crypto/sha1/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.sha1('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.sha1(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] 430ce34d020724ed75a196dfc2ad67c77772d169 +INFO[0000] 430ce34d020724ed75a196dfc2ad67c77772d169 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/09-sha256- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/09-sha256- input- outputEncoding -.md new file mode 100644 index 0000000000..b36f24a98e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/09-sha256- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'sha256( input, outputEncoding )' +description: 'Use SHA-256 to hash input data.' +excerpt: 'Use SHA-256 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/sha256/ +--- + + + +Use [sha256](https://golang.org/pkg/crypto/sha256/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.sha256('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.sha256(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 +INFO[0000] 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/10-sha384- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/10-sha384- input- outputEncoding -.md new file mode 100644 index 0000000000..3f03941fe0 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/10-sha384- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'sha384( input, outputEncoding )' +description: 'Use SHA-384 to hash input data.' +excerpt: 'Use SHA-384 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/sha384/ +--- + + + +Use [sha384](https://golang.org/pkg/crypto/sha512/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.sha384('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.sha384(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] d33d40f7010ce34aa86efd353630309ed5c3d7ffac66d988825cf699f4803ccdf3f033230612f0945332fb580d8af805 +INFO[0000] d33d40f7010ce34aa86efd353630309ed5c3d7ffac66d988825cf699f4803ccdf3f033230612f0945332fb580d8af805 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/11-sha512- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/11-sha512- input- outputEncoding -.md new file mode 100644 index 0000000000..4f9b545b04 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/11-sha512- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'sha512( input, outputEncoding )' +description: 'Use SHA-512 to hash input data.' +excerpt: 'Use SHA-512 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/sha512/ +--- + + + +Use [sha512](https://golang.org/pkg/crypto/sha512/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.sha512('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.sha512(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] db9b1cd3262dee37756a09b9064973589847caa8e53d31a9d142ea2701b1b28abd97838bb9a27068ba305dc8d04a45a1fcf079de54d607666996b3cc54f6b67c +INFO[0000] db9b1cd3262dee37756a09b9064973589847caa8e53d31a9d142ea2701b1b28abd97838bb9a27068ba305dc8d04a45a1fcf079de54d607666996b3cc54f6b67c +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/12-sha512_256- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/12-sha512_256- input- outputEncoding -.md new file mode 100644 index 0000000000..f71f2a3260 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/12-sha512_256- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'sha512_256( input, outputEncoding )' +description: 'Use SHA-512/256 to hash input data.' +excerpt: 'Use SHA-512/256 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/sha512_256/ +--- + + + +Use [sha512_256](https://golang.org/pkg/crypto/sha512/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.sha512_256('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.sha512_256(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] 595b5926068b4828fb1c27db21281e31118b8475cb6c3ceeb09be7b685414d5f +INFO[0000] 595b5926068b4828fb1c27db21281e31118b8475cb6c3ceeb09be7b685414d5f +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/13-sha512_224- input- outputEncoding -.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/13-sha512_224- input- outputEncoding -.md new file mode 100644 index 0000000000..68e7008a03 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/13-sha512_224- input- outputEncoding -.md @@ -0,0 +1,47 @@ +--- +title: 'sha512_224( input, outputEncoding )' +description: 'Use SHA-512/224 to hash input data.' +excerpt: 'Use SHA-512/224 to hash input data.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/sha512_224/ +--- + + + +Use [sha512_224](https://golang.org/pkg/crypto/sha512/) to hash input data. + +| Parameter | Type | Description | +| -------------- | -------------------- | --------------------------------------------------| +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to hash. | +| outputEncoding | string | Describes the type of encoding to use for the hash value. Can be "base64", "base64url", "base64rawurl", "hex" or "binary". | + +### Returns + +| Type | Description | +| -------------- | ----------- | +| string / Array | The hash digest as string (for "base64", "base64url", "base64rawurl", "hex" `outputEncoding`) or raw array of integers (for "binary" `outputEncoding`). | + + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + let hash = crypto.sha512_224('hello world!', 'hex'); + console.log(hash); + const binArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]; + hash = crypto.sha512_224(new Uint8Array(binArray).buffer, 'hex'); + console.log(hash); +} +``` + + + +The above script should result in the following being printed during execution: + +```bash +INFO[0000] bc4ed196f7ba1c20f6fb6be1f91edf8293a35b065d6e7d6fd368c890 +INFO[0000] bc4ed196f7ba1c20f6fb6be1f91edf8293a35b065d6e7d6fd368c890 +``` diff --git a/src/data/markdown/docs/02 javascript api/03 k6-crypto/80-Hasher.md b/src/data/markdown/docs/02 javascript api/03 k6-crypto/80-Hasher.md new file mode 100644 index 0000000000..dd3a729432 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/03 k6-crypto/80-Hasher.md @@ -0,0 +1,51 @@ +--- +title: 'Hasher' +description: 'Object returned by crypto.createHash(). It allows adding more data to be hashed and to extract digests along the way.' +excerpt: 'Object returned by crypto.createHash(). It allows adding more data to be hashed and to extract digests along the way.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-crypto/hasher/ +--- + + + +This object is returned by [crypto.createHash()](/javascript-api/k6-crypto/createhash) +and allows the user to successively add more string data to be hashed, and to extract digests along the way. + +| Name | Type | Description | +| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Hasher.update(string) | function | Add more data to the string we want to create a hash of. Takes one string argument, which is the new data we want to add. | +| Hasher.digest(string) | function | Return a digest from the data added (using `update()`) to the Hasher object so far. Takes one string argument, which is the encoding format to return. This can be either "base64", "base64url", "base64rawurl", "hex" or "binary". See the examples below for details. | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; + +export default function () { + console.log(crypto.sha256('hello world!', 'hex')); + const hasher = crypto.createHash('sha256'); + hasher.update('hello '); + hasher.update('world!'); + console.log(hasher.digest('hex')); + + // Other encodings + console.log('base64:', hasher.digest('base64')); + console.log('base64url:', hasher.digest('base64url')); + console.log('base64rawurl:', hasher.digest('base64rawurl')); + console.log('binary:', new Uint8Array(hasher.digest('binary'))); +} +``` + + + +The above code sample should produce this in its output: + +```bash +INFO[0000] 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 +INFO[0000] 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 +INFO[0000] base64: dQnlvaDHYtK6x/kNdYtbImP6Acy8VCq1498WO+CObKk= +INFO[0000] base64url: dQnlvaDHYtK6x_kNdYtbImP6Acy8VCq1498WO-CObKk= +INFO[0000] base64rawurl: dQnlvaDHYtK6x_kNdYtbImP6Acy8VCq1498WO-CObKk +INFO[0000] binary: 117,9,229,189,160,199,98,210,186,199,249,13,117,139,91,34,99,250,1,204,188,84,42,181,227,223,22,59,224,142,108,169 +``` diff --git a/src/data/markdown/docs/02 javascript api/04 k6-data.md b/src/data/markdown/docs/02 javascript api/04 k6-data.md index c6ee1c0588..aedf38e950 100644 --- a/src/data/markdown/docs/02 javascript api/04 k6-data.md +++ b/src/data/markdown/docs/02 javascript api/04 k6-data.md @@ -2,8 +2,10 @@ title: "k6/data" excerpt: "k6 data API" canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-data/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-data/ --- The data module provides helpers to work with data. +| Class/Method | Description | +| ----- | ----------- | +| [SharedArray](/javascript-api/k6-data/sharedarray) | read-only array like structure that shares memory between VUs | diff --git a/src/data/markdown/docs/02 javascript api/04 k6-data/1-SharedArray.md b/src/data/markdown/docs/02 javascript api/04 k6-data/1-SharedArray.md new file mode 100644 index 0000000000..a32a72d4ac --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/04 k6-data/1-SharedArray.md @@ -0,0 +1,138 @@ +--- +title: SharedArray +excerpt: 'SharedArray is an array-like object that shares the underlying memory between VUs.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-data/sharedarray/ +--- + +`SharedArray` is an array-like object that shares the underlying memory between VUs. +The function executes only once, and its result is saved in memory once. +When a script requests an element, k6 gives a _copy_ of that element. + +You must construct a `SharedArray` in the [`init` context](/using-k6/test-lifecycle). +Its constructor takes a name for the `SharedArray` and a function that needs to return an array object itself: + + +```javascript +import { SharedArray } from 'k6/data'; + +const data = new SharedArray('some name', function () { + const dataArray = []; + // more operations + return dataArray; // must be an array +}); +``` + +The name argument is required. +VUs are completely separate JS VMs, and k6 needs some way to identify the `SharedArray` that it needs to return. +You can have multiple `SharedArrays` and even load only some of them for given VUs, +though this is unlikely to have any performance benefit. + +Supported operations on a `SharedArray` include: +- Getting the number of elements with `length` +- Getting an element by its index using the normal syntax `array[index]` +- Using `for-of` loops + +In most cases, you should be able to reduce the memory usage of an array data structure by wrapping it in a `SharedArray`. +Once constructed, a `SharedArray` is read-only, so **you can't use a SharedArray to communicate data between VUs**. + +
+ +Attempting to instantiate a `SharedArray` outside of the [init context](/using-k6/test-lifecycle/) results in the exception `new SharedArray must be called in the init context`. + +This limitation will eventually be removed, but for now, the implication is that you can use `SharedArray` to populate test data only at the very beginning of your test and not as a result of receiving data from a response (for example). + +
+ + +## Example + + + +```javascript +import { SharedArray } from 'k6/data'; + +const data = new SharedArray('some name', function () { + // All heavy work (opening and processing big files for example) should be done inside here. + // This way it will happen only once and the result will be shared between all VUs, saving time and memory. + const f = JSON.parse(open('./somefile.json')); + return f; // f must be an array +}); + +export default function () { + const element = data[Math.floor(Math.random() * data.length)]; + // do something with element +} +``` + + + +## Performance characteristics + +Internally, the current implementation of `SharedArray` keeps the data marshaled as JSON and unmarshals elements only when they are requested. + +In general, this operation should be unnoticeable (relative to whatever else you do with the data). +But, for small data sets, `SharedArray` might perform worse. +However, this is highly dependent on use case. + +To test this, we ran the following script on version v0.31.0 with 100 VUs. + + + +```javascript +import { check } from 'k6'; +import http from 'k6/http'; +import { SharedArray } from 'k6/data'; + +const n = parseInt(__ENV.N); +function generateArray() { + const arr = new Array(n); + for (let i = 0; i < n; i++) { + arr[i] = { something: 'something else' + i, password: '12314561' }; + } + return arr; +} + +let data; +if (__ENV.SHARED === 'true') { + data = new SharedArray('my data', generateArray); +} else { + data = generateArray(); +} + +export default function () { + const iterationData = data[Math.floor(Math.random() * data.length)]; + const res = http.post('https://httpbin.test.k6.io/anything', JSON.stringify(iterationData), { + headers: { 'Content-type': 'application/json' }, + }); + check(res, { 'status 200': (r) => r.status === 200 }); +} +``` + + + +As the table shows, performance didn't differ much at lower numbers of data lines: +up until around 1000 data lines, `SharedArray` shows little benefit in memory usage +and had a higher upper bound of CPU usage (though not substantially higher). + +At 10k lines and above, the memory savings started to heavily carry over to CPU savings as well. + +| data lines | shared | wall time | CPU % | MEM usage | http requests | +| --- | --- | --- | --- | ---- | --- | +| 100 | true | 2:01:70 | 70-79% | 213-217MB | 92191-98837 | +| 100 | false | 2:01:80 | 74-75% | 224-232MB | 96851-98643 | +| 1000 | true | 2:01:60 | 74-79% | 209-216MB | 98251-98806 | +| 1000 | false | 2:01:90 | 75-77% | 333-339MB | 98069-98951 | +| 10000 | true | 2:01:70 | 78-79% | 213-217MB | 97953-98735 | +| 10000 | false | 2:03:00 | 80-83% | 1364-1400MB | 96816-98852 | +| 100000 | true | 2:02:20 | 78-79% | 238-275MB | 98103-98540 | +| 100000 | false | 2:14:00 | 120-124% | 8.3-9.1GB | 96003-97802 | + +In v0.30.0, the difference in CPU usage at lower numbers was around 10-15%, but it also started to even out at around 10k data lines and was a clear winner at 100k. + +The CPU/memory data came from using `/usr/bin/time`. Refer to the [gist with the raw data](https://gist.github.com/MStoykov/1181cfa6f00bc56b90915155f885e2bb). + +These numbers are purely illustrative: the performance can be affected by any additional processing of the element retrieved from the `SharedArray`, or if an output is in use, or it gets multiple elements, etc. +While `SharedArray` has some CPU usage, +it might turn out to be negligible in a given situation with just 10 elements, or more problematic than the memory usage for a 100k elements. +So, if in doubt, you should probably run some benchmarks and decide which tradeoffs are more important for your use case. + diff --git a/src/data/markdown/docs/02 javascript api/05 k6-encoding.md b/src/data/markdown/docs/02 javascript api/05 k6-encoding.md index b4c1893001..1cf5ce78de 100644 --- a/src/data/markdown/docs/02 javascript api/05 k6-encoding.md +++ b/src/data/markdown/docs/02 javascript api/05 k6-encoding.md @@ -2,7 +2,11 @@ title: "k6/encoding" excerpt: 'The encoding module provides base64 encoding/decoding as defined by RFC4648.' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-encoding/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-encoding/ --- The encoding module provides [base64](https://en.wikipedia.org/wiki/Base64) encoding/decoding as defined by [RFC4648](https://tools.ietf.org/html/rfc4648). + +| Function | Description | +| -------- | ----------- | +| [b64decode(input, [encoding], [format])](/javascript-api/k6-encoding/b64decode/) | Base64 decode a string. | +| [b64encode(input, [encoding])](/javascript-api/k6-encoding/b64encode/) | Base64 encode a string. | diff --git a/src/data/markdown/docs/02 javascript api/05 k6-encoding/b64decode- input- -encoding- -format-.md b/src/data/markdown/docs/02 javascript api/05 k6-encoding/b64decode- input- -encoding- -format-.md new file mode 100644 index 0000000000..09572c5baf --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/05 k6-encoding/b64decode- input- -encoding- -format-.md @@ -0,0 +1,48 @@ +--- +title: 'b64decode( input, [encoding], [format] )' +description: 'Base64 decode a string.' +excerpt: 'Base64 decode a string.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-encoding/b64decode/ +--- + +Decode the passed base64 encoded `input` string into the unencoded original input in either binary or string formats. + +| Parameter | Type | Description | +| ------------------- | ------ | ------------ | +| input | string | The string to base64 decode. | +| encoding (optional) | string | The base64 encoding to use.
Available options are:
- **"std"**: the standard encoding with `=` padding chars and `+` and `/` characters in encoding alphabet. This is the default.
- **"rawstd"**: like `std` but without `=` padding characters.
- **"url"**: URL safe version of `std`, encoding alphabet doesn't contain `+` and `/` characters, but rather `-` and `_` characters.
- **"rawurl"**: like `url` but without `=` padding characters. | +| format (optional) | string | If `"s"` return the data as a string, otherwise if unspecified an ArrayBuffer object is returned. + +### Returns + +| Type | Description | +| -------------------- | ------------------------------------------------- | +| ArrayBuffer / string | The base64 decoded version of the `input` string in either string or ArrayBuffer format, depending on the `format` parameter. | + +### Example + + + +```javascript +import { check } from 'k6'; +import encoding from 'k6/encoding'; + +export default function () { + const str = 'hello world'; + const enc = 'aGVsbG8gd29ybGQ='; + const expBin = new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]); + check(null, { + 'is decoding to string correct': () => encoding.b64decode(enc, 'std', 's') === str, + 'is decoding to ArrayBuffer correct': () => { + const decBin = new Uint8Array(encoding.b64decode(enc)); + if (decBin.length != expBin.length) return false; + for (let i = 0; i < decBin.length; i++) { + if (decBin[i] !== expBin[i]) return false; + } + return true; + }, + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/05 k6-encoding/b64encode- input- -encoding- -.md b/src/data/markdown/docs/02 javascript api/05 k6-encoding/b64encode- input- -encoding- -.md new file mode 100644 index 0000000000..97b2d8e30f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/05 k6-encoding/b64encode- input- -encoding- -.md @@ -0,0 +1,38 @@ +--- +title: 'b64encode( input, [encoding] )' +description: 'Encode data in base64.' +excerpt: 'Encode data in base64.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-encoding/b64encode/ +--- + +| Parameter | Type | Description | +| ------------------- | ------ | ------------------------------------------------------------------------ | +| input | string / ArrayBuffer | The input string or `ArrayBuffer` object to base64 encode. | +| encoding (optional) | string | The base64 encoding to use.
Available options are:
- **"std"**: the standard encoding with `=` padding chars and `+` and `/` characters in encoding alphabet. This is the default.
- **"rawstd"**: like `std` but without `=` padding characters.
- **"url"**: URL safe version of `std`, encoding alphabet doesn't contain `+` and `/` characters, but rather `-` and `_` characters.
- **"rawurl"**: like `url` but without `=` padding characters. | + +### Returns + +| Type | Description | +| ------ | ---------------------------------------- | +| string | The base64 encoding of the `input` data. | + +### Example + + + +```javascript +import { check } from 'k6'; +import encoding from 'k6/encoding'; + +export default function () { + const str = 'hello world'; + const enc = 'aGVsbG8gd29ybGQ='; + const buf = new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]).buffer; + check(null, { + 'is encoding string correct': () => encoding.b64encode(str) === enc, + 'is encoding ArrayBuffer correct': () => encoding.b64encode(buf) === enc, + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/06 k6-execution.md b/src/data/markdown/docs/02 javascript api/06 k6-execution.md index 4126f11f83..0b95bacbfa 100644 --- a/src/data/markdown/docs/02 javascript api/06 k6-execution.md +++ b/src/data/markdown/docs/02 javascript api/06 k6-execution.md @@ -2,7 +2,259 @@ title: "k6/execution" excerpt: "Get information about the current test's execution state." canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-execution/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-execution/ --- `k6/execution` provides the capability to get information about the current test execution state inside the test script. You can read in your script the execution state during the test execution and change your script logic based on the current state. + +The `k6/execution` module provides the test execution information with the following properties: + +- [instance](#instance) +- [scenario](#scenario) +- [test](#test) +- [vu](#vu) + +
+ +```javascript +import exec from 'k6/execution'; + +export const options = { + scenarios: { + myscenario: { + // this will be the returned name + executor: 'shared-iterations', + maxDuration: '30m', + }, + }, +}; + +export default function () { + console.log(exec.scenario.name); // myscenario +} +``` + +
+ +> ℹ️ **Identifiers** +> +> All unique identifiers are sequentially generated starting from a base of zero (iterations) or one (VU IDs). In distributed/cloud test runs, the test-wide iteration numbers and VU identifiers are still going to be unique across instances, though there might be gaps in the sequences when, for example, some instances execute faster iterations than others or allocate more VUs mid-test. + + +### instance + +The instance object provides information associated with the load generator instance. You can think of it as the current running k6 process, which will likely be a single process if you are running k6 on your local machine. When running a cloud/distributed test with multiple load generator instances, the values of the following properties can differ across instances. + +| Property | Type | Description | +|----------|------|-------------| +| iterationsInterrupted | integer | The number of prematurely interrupted iterations in the current instance. | +| iterationsCompleted | integer | The number of completed iterations in the current instance. | +| vusActive | integer | The number of active VUs. | +| vusInitialized | integer | The number of currently initialized VUs. | +| currentTestRunDuration | float | The time passed from the start of the current test run in milliseconds. | + +### scenario + +Meta information and execution details about the current running [scenario](/using-k6/scenarios). + +| Property | Type | Description | +|----------|------|-------------| +| name | string | The assigned name of the running scenario. | +| executor | string | The name of the running [Executor](/using-k6/scenarios/#executors) type. | +| startTime | integer | The Unix timestamp in milliseconds when the scenario started. | +| progress | float | Percentage in a 0 to 1 interval of the scenario progress. | +| iterationInInstance | integer | The unique and zero-based sequential number of the current iteration in the scenario, across the current instance. | +| iterationInTest | integer | The unique and zero-based sequential number of the current iteration in the scenario. It is unique in all k6 execution modes - in local, cloud and distributed/segmented test runs. However, while every instance will get non-overlapping index values in cloud/distributed tests, they might iterate over them at different speeds, so the values won't be sequential across them. | + + +### test + +Control the test execution. + +| Property | Type | Description | +|----------|------|-------------| +| abort([String]) | function | It aborts the test run with the exit code `108`, and an optional string parameter can provide an error message. Aborting the test will not prevent the `teardown()` execution. | +| options | Object | It returns an object with all the test options as properties. The options' values are consolidated following the [order of precedence](/using-k6/k6-options/how-to#order-of-precedence) and derived if shortcuts have been used. It returns `null` for properties where the relative option hasn't been defined. | + +### vu + +Meta information and execution details about the current vu. + +| Property | Type | Description | +|----------|------|-------------| +| iterationInInstance | integer | The identifier of the iteration in the current instance for this VU. This is only unique for current VU and this instance (if multiple instances). This keeps being aggregated if a given VU is reused between multiple scenarios. | +| iterationInScenario | integer | The identifier of the iteration in the current scenario for this VU. This is only unique for current VU and scenario it is currently executing. | +| idInInstance | integer | The identifier of the VU across the instance. Not unique across multiple instances. | +| idInTest | integer | The globally unique (across the whole test run) identifier of the VU. | +| metrics.tags | object | The map that gives control over [VU's Tags](/using-k6/tags-and-groups/#tags). The Tags will be included in every metric emitted by the VU and the Tags' state is maintained across different iterations of the same Scenario while the VU exists. Check how to use it in the [example](#tags) below. | +| metrics.metadata | object | The map that gives control over VU's Metadata. The Metadata will be included in every metric emitted by the VU and the Metadata's state is maintained across different iterations of the same Scenario while the VU exists. Check how to use it in the [example](#metadata) below. | + + + +Setting a Tag with the same key as a [system tag](/using-k6/k6-options/reference#system-tags) is allowed, but it requires attention to avoid unexpected results. Overwriting system tags will not throw an error, but in most cases will not actually change the value of the emitted metrics as expected. For example, trying to set the `url` tag value will not result in a changed tag value when `http.get()` is called, since the tag value is determined by the HTTP request itself. However, it will add the tag `url` to the metric samples emitted by a `check()` or `metric.add()`, which is probably not the desired behavior. On the other hand, setting the `name` tag will work as expected, since that was already supported for `http.*` methods, for the purposes of the [URL Grouping](/using-k6/http-requests/#url-grouping) feature. + +Not all the types are accepted as a tag value: k6 supports strings, numbers and boolean types. Under the hood, the `tags` object handles a Tag as a `String` key-value pair, so all the types will be implicitly converted into a string. If one of the denied types is used (e.g. Object or Array) and the [`throw` option](/using-k6/k6-options/reference/#throw) is set, an exception will be thrown. Otherwise, only a warning is printed and the tag value will be discarded. + + + +## Examples and use cases + +### Getting unique data once + +This is a common use case for data parameterization, you can read the [examples](/examples/data-parameterization#retrieving-unique-data) using `scenario.iterationInTest` and `vu.idInTest`. + +### Timing operations + +The `startTime` property from the `scenario` object can be used to time operations. + + + +```javascript +import exec from 'k6/execution'; + +export default function () { + // do some long operations + // ... + console.log(`step1: scenario ran for ${new Date() - new Date(exec.scenario.startTime)}ms`); + + // some more long operations + //... + console.log(`step2: scenario ran for ${new Date() - new Date(exec.scenario.startTime)}ms`); +} +``` + + + +### Script naming +The `name` property can be used for executing the logic based on which script is currently running. + +> **Tip**: +> If you need to run [multiple scenarios](/using-k6/scenarios/advanced-examples/#using-multiple-scenarios) in your script you can use `exec` option achieve a similar goal + + + +```javascript +import exec from 'k6/execution'; + +export const options = { + scenarios: { + 'the-first': { + // ... + }, + 'the-second': { + // ... + }, + }, +}; + +export default function () { + if (exec.scenario.name === 'the-first') { + // do some logic during this scenario + } else { + // do some other logic in the others + } +} +``` + + + +### Test Abort + +Aborting is possible during initialization: + + + +```javascript +import exec from 'k6/execution'; +exec.test.abort(); +``` + + + +As well as inside the `default` function: + + + +```javascript +import exec from 'k6/execution'; + +export default function () { + // Note that you can abort with a specific message too + exec.test.abort('this is the reason'); +} + +export function teardown() { + console.log('teardown will still be called after test.abort()'); +} +``` + + + +### Get test options + +Get the consolidated and derived options' values + + + +```javascript +import exec from 'k6/execution'; + +export const options = { + stages: [ + { duration: '5s', target: 100 }, + { duration: '5s', target: 50 }, + ], +}; + +export default function () { + console.log(exec.test.options.paused); // null + console.log(exec.test.options.scenarios.default.stages[0].target); // 100 +} +``` + + + +### Tags +The `vu.metrics.tags` property can be used for getting or setting [VU's tags](/using-k6/tags-and-groups/#tags). + + + +```javascript +import http from 'k6/http'; +import exec from 'k6/execution'; + +export default function () { + exec.vu.metrics.tags['mytag'] = 'value1'; + exec.vu.metrics.tags['mytag2'] = 2; + + // the metrics these HTTP requests emit will get tagged with `mytag` and `mytag2`: + http.batch(['https://test.k6.io', 'https://test-api.k6.io']); +} +``` + + + +`vu.tags` (without `metrics`) can also be used, but is deprecated for the more context-specific variant. + + +### Metadata +The `vu.metrics.metadata` property can be used for getting or setting VU's metadata. It is similar to `tags`, but can be used for high cardinality data. It also can not be used in thresholds and will likely be handled differently by each output. + + + +```javascript +import http from 'k6/http'; +import exec from 'k6/execution'; + +export default function () { + exec.vu.metrics.metadata['trace_id'] = 'somecoolide'; + + // the metrics these HTTP requests emit will get the metadata `trace_id`: + http.batch(['https://test.k6.io', 'https://test-api.k6.io']); + + delete exec.vu.metrics.metadata['trace_id'] // this will unset it + // which will make the metrics these requests to not have the metadata `trace_id` set on them. + http.batch(['https://test.k6.io', 'https://test-api.k6.io']); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental.md index 03f6a25c80..e9b78feb0b 100644 --- a/src/data/markdown/docs/02 javascript api/07 k6-experimental.md +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental.md @@ -2,5 +2,16 @@ title: "k6/experimental" excerpt: "k6 experimental APIs" canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/ --- + + + +| Modules | Description | +| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| [browser](/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](/javascript-api/k6-experimental/redis/) | Functionality to interact with [Redis](https://redis.io/). | +| [timers](/javascript-api/k6-experimental/timers/) | `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` | +| [tracing](/javascript-api/k6-experimental/tracing/) | Support for instrumenting HTTP requests with tracing information. | +| [webcrypto](/javascript-api/k6-experimental/webcrypto/) | Implements the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). | +| [websockets](/javascript-api/k6-experimental/websockets/) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). | +| [grpc](/javascript-api/k6-experimental/grpc/) | Extends `k6/net/grpc` with the streaming capabilities. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser.md new file mode 100644 index 0000000000..3507b28bf7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser.md @@ -0,0 +1,258 @@ +--- +title: 'browser' +excerpt: 'An overview of the browser-level APIs from browser module.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/browser/ +--- + + + +The browser module APIs aim for rough compatibility with the [Playwright API for NodeJS](https://playwright.dev/docs/api/class-playwright). + +Note that because k6 does not run in NodeJS, the browser module APIs will slightly differ from their Playwright counterparts. + +You can find examples of using [the browser module API](#browser-module-api) in our [getting started guide](/using-k6-browser). + +
+ +To work with the browser module, make sure you are using the latest [k6 version](https://github.com/grafana/k6/releases). + +
+ +## Properties + +The table below lists the properties you can import from the browser module (`'k6/experimental/browser'`). + +| Property | Description | +|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| browser | The browser module API is the entry point for all your tests. See the [example](#example) and the [API](#browser-module-api) below. | +| devices | Returns predefined emulation settings for many end-user devices that can be used to simulate browser behavior on a mobile device. See the [devices example](#devices-example) below. | + + +## Browser Module API + +The browser module is the entry point for all your tests, and it is what interacts with the actual web browser via [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) (CDP). It manages: +- [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) which is where you can set a variety of attributes to control the behavior of pages; +- and [Page](/javascript-api/k6-experimental/browser/page/) which is where your rendered site is displayed. + +| Method | Description | +|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| [browser.context()](/javascript-api/k6-experimental/browser/context) | Returns the current [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/). | +| [browser.isConnected](/javascript-api/k6-experimental/browser/isconnected) | Indicates whether the [CDP](https://chromedevtools.github.io/devtools-protocol/) connection to the browser process is active or not. | +| [browser.newContext([options])](/javascript-api/k6-experimental/browser/newcontext/) | Creates and returns a new [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/). | +| [browser.newPage([options])](/javascript-api/k6-experimental/browser/newpage) | Creates a new [Page](/javascript-api/k6-experimental/browser/page/) in a new [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) and returns the page. Pages that have been opened ought to be closed using [`Page.close`](/javascript-api/k6-experimental/browser/page/close/). Pages left open could potentially distort the results of Web Vital metrics. | +| [browser.version()](/javascript-api/k6-experimental/browser/version/) | Returns the browser application's version. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + try { + await page.goto('https://test.k6.io/'); + } finally { + page.close(); + } +} +``` + + + +Then, you can run the test with this command. Also, see the [browser module options](/javascript-api/k6-experimental/browser/#browser-module-options) for customizing the browser module's behavior using environment variables. + + + +```bash +$ k6 run script.js +``` + +```bash +# WARNING! +# The grafana/k6:master-with-browser image launches a Chrome browser by setting the +# 'no-sandbox' argument. Only use it with trustworthy websites. +# +# As an alternative, you can use a Docker SECCOMP profile instead, and overwrite the +# Chrome arguments to not use 'no-sandbox' such as: +# docker container run --rm -i -e K6_BROWSER_ARGS='' --security-opt seccomp=$(pwd)/chrome.json grafana/k6:master-with-browser run - k6 run script.js +``` + +```bash +PS C:\k6> k6 run script.js +``` + + + + + + +## Browser-level APIs + +| k6 Class | Description | +|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) | Enables independent browser sessions with separate [Page](/javascript-api/k6-experimental/browser/page/)s, cache, and cookies. | +| [ElementHandle](/javascript-api/k6-experimental/browser/elementhandle/) | Represents an in-page DOM element. | +| [Frame](/javascript-api/k6-experimental/browser/frame/) | Access and interact with the [`Page`](/javascript-api/k6-experimental/browser/page/).'s `Frame`s. | +| [JSHandle](/javascript-api/k6-experimental/browser/jshandle) | Represents an in-page JavaScript object. | +| [Keyboard](/javascript-api/k6-experimental/browser/keyboard/) | Used to simulate the keyboard interactions with the associated [`Page`](/javascript-api/k6-experimental/browser/page/). | +| [Locator](/javascript-api/k6-experimental/browser/locator/) | The Locator API makes it easier to work with dynamically changing elements. | +| [Mouse](/javascript-api/k6-experimental/browser/mouse/) | Used to simulate the mouse interactions with the associated [`Page`](/javascript-api/k6-experimental/browser/page/). | +| [Page](/javascript-api/k6-experimental/browser/page/) | Provides methods to interact with a single tab in a browser. | +| [Request](/javascript-api/k6-experimental/browser/request/) | Used to keep track of the request the [`Page`](/javascript-api/k6-experimental/browser/page/) makes. | +| [Response](/javascript-api/k6-experimental/browser/response/) | Represents the response received by the [`Page`](/javascript-api/k6-experimental/browser/page/). | +| [Touchscreen](/javascript-api/k6-experimental/browser/touchscreen/) | Used to simulate touch interactions with the associated [`Page`](/javascript-api/k6-experimental/browser/page/). | +| [Worker](/javascript-api/k6-experimental/browser/worker/) | Represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). | + + +## Browser Module Options + +You can customize the behavior of the browser module by providing browser options as environment variables. + +| Environment Variable | Description | +| -------------------- | ----------- | +| K6_BROWSER_ARGS | Extra command line arguments to include when launching browser process. See [this link](https://peter.sh/experiments/chromium-command-line-switches/) for a list of Chromium arguments. Note that arguments should not start with `--` (see the [example](#example)). | +| K6_BROWSER_DEBUG | All CDP messages and internal fine grained logs will be logged if set to `true`. | +| K6_BROWSER_EXECUTABLE_PATH | Override search for browser executable in favor of specified absolute path. | +| K6_BROWSER_HEADLESS | Show browser GUI or not. `true` by default. | +| K6_BROWSER_IGNORE_DEFAULT_ARGS | Ignore any of the [default arguments](#default-arguments) included when launching a browser process. | +| K6_BROWSER_TIMEOUT | Default timeout to use for various actions and navigation. `'30s'` if not set. | + +The following command passes the [browser module options](#browser-module-options) as environment variables to launch a headful browser with custom arguments. + + + +```bash +$ K6_BROWSER_HEADLESS=false K6_BROWSER_ARGS='show-property-changed-rects' k6 run script.js +``` +```bash +# WARNING! +# The grafana/k6:master-with-browser image launches a Chrome browser by setting the +# 'no-sandbox' argument. Only use it with trustworthy websites. +# +# As an alternative, you can use a Docker SECCOMP profile instead, and overwrite the +# Chrome arguments to not use 'no-sandbox' such as: +# docker container run --rm -i -e K6_BROWSER_ARGS='' --security-opt seccomp=$(pwd)/chrome.json grafana/k6:master-with-browser run - set "K6_BROWSER_HEADLESS=false" && set "K6_BROWSER_ARGS='show-property-changed-rects' " && k6 run script.js +``` + +```bash +PS C:\k6> $env:K6_BROWSER_HEADLESS="false" ; $env:K6_BROWSER_ARGS='show-property-changed-rects' ; k6 run script.js +``` + + + + +## Default arguments + +List of default arguments included when launching the browser process. You can pass one or more of the arguments to the `K6_BROWSER_IGNORE_DEFAULT_ARGS` environment variable when starting a test for the ones you want to ignore. + +
+ +The starting '--' have been omitted from the argument names in these lists. + +
+ +| Argument | Value | Description | +|----------|--------|--------------------------------------------------------| +| disable-background-networking | `true` | Disables several subsystems which run network requests in the background. This is used during network performance testing to avoid measurement noise. | +| enable-features | NetworkService,
NetworkServiceInProcess | Comma-separated list of feature names to enable. | +| disable-background-timer-throttling | `true` | Disables task throttling of timer tasks from background pages. | +| disable-backgrounding-occluded-windows | `true` | Disables backgrounding renders for occluded windows. Done for tests to avoid nondeterministic behavior. | +| disable-breakpad | `true` | Disables the crash reporting. | +| disable-component-extensions
-with-background-pages | `true` | Disables default component extensions with background pages. Useful for performance tests where these pages may interfere with results. | +| disable-default-apps | `true` | Disables the installation of default apps on the first run. This is used during automated testing. | +| disable-dev-shm-usage | `true` | The /dev/shm partition is too small in certain VM environments, causing Chrome to fail or crash. This flag provides a work-around for this issue (a temporary directory will always be used to create anonymous shared memory files). | +| disable-extensions | `true` | Disables extensions. | +| disable-features | ImprovedCookieControls,
LazyFrameLoading,
GlobalMediaControls,
DestroyProfileOnBrowserClose,
MediaRouter,
AcceptCHFrame | Comma-separated list of feature names to disable. | +| disable-hang-monitor | `true` | Suppresses hang monitor dialogs in renderer processes. This may allow slow unload handlers on a page to prevent the tab from closing, but the Task Manager can be used to terminate the offending process in this case. | +| disable-ipc-flooding-protection | `true` | Disables the IPC flooding protection. It is activated by default. Some javascript functions can be used to flood the browser process with IPC. This protection limits the rate at which they can be used. | +| disable-popup-blocking | `true` | Disables pop-up blocking. | +| disable-prompt-on-repost | `true` | Usually, when the user attempts to navigate to a page that was the result of a post request, the browser prompts to make sure that's the intention of the user. This switch may be used to disable that check during automated testing. | +| disable-renderer-backgrounding | `true` | Prevents renderer process backgrounding when set. | +| force-color-profile | `srgb` | Forces all monitors to be treated as though they have the specified color profile. Accepted values are "srgb" and "generic-rgb" (currently used by Mac layout tests) and "color-spin-gamma24" (used by layout tests). | +| metrics-recording-only | `true` | Enables the recording of metrics reports but disables reporting. This executes all the code that a normal client would use for reporting, except the report is dropped rather than sent to the server. This is useful for finding issues in the metrics code during UI and performance tests. | +| no-first-run | `true` | Skips the "First Run" tasks, whether or not it's the first run, and the "What's New" page. This does not drop the "First Run" sentinel and thus doesn't prevent "First Run" from occurring the next time Chromium is launched without this flag. It also does not update the last "What's New" milestone, so it does not prevent "What's New" from occurring the next time Chromium is launched without this flag. | +| enable-automation | `true` | Enables indication that the browser is controlled by automation. | +| password-store | `basic` | Specifies which encryption storage backend to use. The possible values are kwallet, kwallet5, gnome, gnome-keyring, gnome-libsecret, and basic. Any other value will lead to Chromium detecting the best backend automatically. | +| use-mock-keychain | `true` | Uses mock keychain on Mac to prevent the blocking permissions dialog about: "Chrome wants to use your confidential information stored in your keychain." | +| no-service-autorun | `true` | Disables the service process from adding itself as an autorun process. This does not delete existing autorun registrations, it just prevents the service from registering a new one. | +| no-startup-window | `true` | Does not automatically open a browser window on startup (used when launching Chrome for the purpose of hosting background apps). | +| no-default-browser-check | `true` | Disables the default browser check. Useful for UI/browser tests where we want to avoid having the default browser info-bar displayed. | +| headless | `true`/`false` | Run in headless mode, i.e., without a UI or display server dependencies. Set by `K6_BROWSER_HEADLESS` environment variable (default true). | +| window-size | `800,600` | Sets the initial window size. Provided as string in the format "800,600". | + +Additionally if headless mode is set to `true` in [browser options](/javascript-api/k6-experimental/browser#browser_options), the following arguments are also set: + +| Argument | Value | Description | +|------------|--------|--------------------------------------------------------| +| hide-scrollbars | `true` | Prevents creating scrollbars for web content. Useful for taking consistent screenshots. | +| mute-audio | `true` | Mutes audio sent to the audio device so it is not audible during automated testing. | +| blink-settings | primaryHoverType=2,availableHoverTypes=2,
primaryPointerType=4,availablePointerTypes=4 | Sets blink settings. Format is [=],[=],... The names are declared in [settings.json5](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/settings.json5) from chromium project. For boolean type, use "true", "false", or omit '=' part to set to true. For enum type, use the int value of the enum value. | + +## Devices Example + +To emulate the browser behaviour on a mobile device and approximately measure the browser performance, you can import `devices` from `k6/experimental/browser`. + + + +```javascript +import { browser, devices } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const iphoneX = devices['iPhone X']; + const context = browser.newContext(iphoneX); + const page = context.newPage(); + + try { + await page.goto('https://test.k6.io/'); + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext.md new file mode 100644 index 0000000000..1694806f13 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext.md @@ -0,0 +1,28 @@ +--- +title: "BrowserContext" +excerpt: "Browser module: BrowserContext Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/ +--- + +`BrowserContext`s provide a way to operate multiple independent sessions, with separate pages, cache, and cookies. A default `BrowserContext` is created when a browser is launched. + +The [browser module API](/javascript-api/k6-experimental/browser#browser-module-api) is used to create a new `BrowserContext`. + +If a [page](/javascript-api/k6-experimental/browser/page/) opens another page, e.g. with a `window.open` call, the popup will belong to the parent page's `BrowserContext`. + + +| Method | Description | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| [BrowserContext.addCookies()](/javascript-api/k6-experimental/browser/browsercontext/addcookies/) | Adds [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) into the `BrowserContext`. | +| [BrowserContext.clearCookies()](/javascript-api/k6-experimental/browser/browsercontext/clearcookies/) | Clear the `BrowserContext`'s [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie). | +| [BrowserContext.clearPermissions()](/javascript-api/k6-experimental/browser/browsercontext/clearpermissions) | Clears all permission overrides for the `BrowserContext`. | +| [BrowserContext.cookies()](/javascript-api/k6-experimental/browser/browsercontext/cookies) | Returns a list of [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) from the `BrowserContext`. | +| [BrowserContext.close()](/javascript-api/k6-experimental/browser/browsercontext/close) | Close the `BrowserContext` and all its [page](/javascript-api/k6-experimental/browser/page/)s. | +| [BrowserContext.grantPermissions(permissions[, options])](/javascript-api/k6-experimental/browser/browsercontext/grantpermissions) | Grants specified permissions to the `BrowserContext`. | +| [BrowserContext.newPage()](/javascript-api/k6-experimental/browser/browsercontext/newpage) | Uses the `BrowserContext` to create a new [Page](/javascript-api/k6-experimental/browser/page/) and returns it. | +| [BrowserContext.pages()](/javascript-api/k6-experimental/browser/browsercontext/pages) | Returns a list of [page](/javascript-api/k6-experimental/browser/page/)s that belongs to the `BrowserContext`. | +| [BrowserContext.setDefaultNavigationTimeout(timeout)](/javascript-api/k6-experimental/browser/browsercontext/setdefaultnavigationtimeout) | Sets the default navigation timeout in milliseconds. | +| [BrowserContext.setDefaultTimeout(timeout)](/javascript-api/k6-experimental/browser/browsercontext/setdefaulttimeout) | Sets the default maximum timeout for all methods accepting a timeout option in milliseconds. | +| [BrowserContext.setGeolocation(geolocation)](/javascript-api/k6-experimental/browser/browsercontext/setgeolocation) | Sets the `BrowserContext`'s geolocation. | +| [BrowserContext.setOffline(offline)](/javascript-api/k6-experimental/browser/browsercontext/setoffline) | Toggles the `BrowserContext`'s connectivity on/off. | +| [BrowserContext.waitForEvent(event[, optionsOrPredicate])](/javascript-api/k6-experimental/browser/browsercontext/waitforevent) | Waits for the event to fire and passes its value into the predicate function. | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/addCookies.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/addCookies.md new file mode 100644 index 0000000000..186d471b53 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/addCookies.md @@ -0,0 +1,89 @@ +--- +title: 'addCookies()' +excerpt: 'Clears context cookies.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/addcookies/ +--- + +Adds a list of [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) into the [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/cookie). All pages within this [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/cookie) will have these [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) set. + +
+ +If a [cookie](/javascript-api/k6-experimental/browser/browsercontext/cookie)'s `url` property is not provided, both `domain` and `path` properties must be specified. + +
+ + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const context = browser.newContext(); + const page = context.newPage(); + + try { + const unixTimeSinceEpoch = Math.round(new Date() / 1000); + const day = 60*60*24; + const dayAfter = unixTimeSinceEpoch+day; + const dayBefore = unixTimeSinceEpoch-day; + + context.addCookies([ + // this cookie expires at the end of the session + { + name: 'testcookie', + value: '1', + sameSite: 'Strict', + domain: 'httpbin.org', + path: '/', + httpOnly: true, + secure: true, + }, + // this cookie expires in a day + { + name: 'testcookie2', + value: '2', + sameSite: 'Lax', + domain: 'httpbin.org', + path: '/', + expires: dayAfter, + }, + // this cookie expires in the past, so it will be removed. + { + name: 'testcookie3', + value: '3', + sameSite: 'Lax', + domain: 'httpbin.org', + path: '/', + expires: dayBefore + } + ]); + + const response = await page.goto('https://httpbin.org/cookies', { + waitUntil: 'networkidle', + }); + console.log(response.json()); + // prints: + // {"cookies":{"testcookie":"1","testcookie2":"2"}} + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/clearCookies.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/clearCookies.md new file mode 100644 index 0000000000..e87efb6b0b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/clearCookies.md @@ -0,0 +1,41 @@ +--- +title: 'clearCookies()' +excerpt: 'Clears context cookies.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/clearcookies/ +--- + +Clears the `BrowserContext`'s cookies. + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const context = browser.newContext(); + const page = context.newPage(); + + await page.goto('https://httpbin.org/cookies/set?testcookie=testcookievalue'); + console.log(context.cookies().length); // prints: 1 + + context.clearCookies(); + console.log(context.cookies().length); // prints: 0 +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/clearPermissions.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/clearPermissions.md new file mode 100644 index 0000000000..5d1f1f1bfe --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/clearPermissions.md @@ -0,0 +1,45 @@ +--- +title: 'clearPermissions()' +excerpt: 'Clears all permission overrides for the BrowserContext.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/clearpermissions/ +--- + +
+ +This feature has known issues. +For details, refer to [issue #443](https://github.com/grafana/xk6-browser/issues/443). + +
+ +Clears all permission overrides for the `BrowserContext`. + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const context = browser.newContext(); + context.grantPermissions(['clipboard-read']); + // do stuff ... + context.clearPermissions(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/close.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/close.md new file mode 100644 index 0000000000..4b6501d69d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/close.md @@ -0,0 +1,38 @@ +--- +title: 'close()' +excerpt: 'Close the BrowserContext and all its pages.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/close/ +--- + +Close the `BrowserContext` and all its [page](/javascript-api/k6-experimental/browser/page/)s. The `BrowserContext` is unusable after this call and a new one must be created. This is typically called to cleanup before ending the test. + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const context = browser.newContext(); + context.newPage(); + + context.close(); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/cookie.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/cookie.md new file mode 100644 index 0000000000..609f455782 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/cookie.md @@ -0,0 +1,21 @@ +--- +title: "Cookie" +excerpt: "Browser module: Cookie Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/cookie/ +--- + +Cookie class represents a cookie in the [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext). + +See the [HTTP Cookies documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) on the Mozilla website for more details about cookies. + +| Property | Type | Default | Description | +| -------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| name | string | `""` | The cookie's name. Required. | +| value | string | `""` | The cookie's value. Required. | +| domain | string | `""` | The cookie's domain. | +| path | string | `'/'` | The cookie's path. | +| url | string | `""` | The cookie's URL. | +| expires | number | `-1` | The cookie's expiration date as the number of seconds since the UNIX epoch. `-1` means a session cookie. | +| httpOnly | bool | `false` | A cookie is inaccessible to the JavaScript [document.cookie](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) API when this property is `true`. | +| secure | bool | `false` | The cookie's secure flag. | +| sameSite | string | `'Lax'` | The cookie's same site flag. It can be one of `'Strict'`, `'Lax'`, and `'None'`. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/cookies.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/cookies.md new file mode 100644 index 0000000000..526084370d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/cookies.md @@ -0,0 +1,81 @@ +--- +title: 'cookies([urls])' +excerpt: 'Retrieves context cookies.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/cookies/ +--- + +Returns a list of [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) from the [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext) filtered by the provided `urls`. If no `urls` are provided, all cookies are returned. + +| Parameter | Type | Description | +|----------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| urls | array | A string array of URLs to filter the [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) in the [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext). | + +### Returns + +| Type | Description | +| ---- | ----------- | +| array | A list of [cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie). | + +
+ +[Cookies](/javascript-api/k6-experimental/browser/browsercontext/cookie) can be added with [BrowserContext.addCookies](/javascript-api/k6-experimental/browser/browsercontext/addcookies/). + +
+ +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + ui: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +}; + +export default async function () { + const context = browser.newContext(); + const page = context.newPage(); + + try { + // get cookies from the browser context + let cookies = context.cookies(); + console.log("initial cookies length:", cookies.length); // prints 0 + + // let's add more cookies to filter by urls + context.addCookies([ + { name: 'foo', value: 'foovalue', sameSite: 'Strict', url: 'http://foo.com' }, + { name: 'bar', value: 'barvalue', sameSite: 'Lax', url: 'https://bar.com' }, + { name: 'baz', value: 'bazvalue', sameSite: 'Lax', url: 'https://baz.com' } + ]); + + // get all cookies + cookies = context.cookies(); + console.log("filtered cookies length:", cookies.length); // prints 3 + + // get cookies filtered by urls + cookies = context.cookies('http://foo.com', 'https://baz.com'); + console.log("filtered cookies length:", cookies.length); // prints 2 + + // the first filtered cookie + console.log("1st cookie's name :", cookies[0].name); // prints foo + console.log("1st cookie's value:", cookies[0].value); // prints foovalue + // the first filtered cookie + console.log("2nd cookie's name :", cookies[1].name); // prints baz + console.log("2nd cookie's value:", cookies[1].value); // prints bazvalue + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/grantPermissions.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/grantPermissions.md new file mode 100644 index 0000000000..df175440aa --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/grantPermissions.md @@ -0,0 +1,48 @@ +--- +title: 'grantPermissions(permissions[, options])' +excerpt: 'Grants specified permissions to the BrowserContext.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/grantpermissions/ +--- + +Grants specified permissions to the `BrowserContext`. Only grants corresponding permissions to the given origin if specified. + + + +| Parameter | Type | Description | +|----------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| permissions | array | A string array of permissions to grant. A permission can be one of the following values: `'geolocation'`, `'midi'`, `'midi-sysex'` (system-exclusive midi), `'notifications'`, `'camera'`, `'microphone'`, `'background-sync'`, `'ambient-light-sensor'`, `'accelerometer'`, `'gyroscope'`, `'magnetometer'`, `'accessibility-events'`, `'clipboard-read'`, `'clipboard-write'`, `'payment-handler'`. | +| options | object | Optional. | +| options.origin | string | The [origin](https://developer.mozilla.org/en-US/docs/Glossary/Origin) to grant permissions to, e.g. `'https://example.com'`. | + + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const context = browser.newContext(); + context.grantPermissions(['clipboard-read', 'clipboard-write'], { + origin: 'https://example.com/', + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/newPage.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/newPage.md new file mode 100644 index 0000000000..bd44d02045 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/newPage.md @@ -0,0 +1,35 @@ +--- +title: 'newPage()' +excerpt: 'Creates a new page inside this BrowserContext.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/newpage/ +--- + +Uses the `BrowserContext` to create a new [Page](/javascript-api/k6-experimental/browser/page/) and returns it. + + +### Returns + +| Type | Description | +| ------ | ------------------------------------------------------- | +| object | A new [Page](/javascript-api/k6-experimental/browser/page/) object. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export default async function () { + const page = browser.newPage(); + + try { + await page.goto('https://test.k6.io/browser.php'); + } finally { + page.close(); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/pages.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/pages.md new file mode 100644 index 0000000000..4e432931a5 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/pages.md @@ -0,0 +1,53 @@ +--- +title: 'pages()' +excerpt: 'Returns a list of pages inside this BrowserContext.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/pages/ +--- + +
+ +This feature has **known issues**. For details, refer to +[#444](https://github.com/grafana/xk6-browser/issues/444). + +
+ +Returns all open [Page](/javascript-api/k6-experimental/browser/page/)s in the `BrowserContext`. + + +### Returns + +| Type | Description | +| ------ | --------------- | +| array | All open pages. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const context = browser.newContext(); + context.newPage(); + const pages = context.pages(); + console.log(pages.length); // 1 + context.close(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setDefaultNavigationTimeout.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setDefaultNavigationTimeout.md new file mode 100644 index 0000000000..52a95c9ff3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setDefaultNavigationTimeout.md @@ -0,0 +1,47 @@ +--- +title: 'setDefaultNavigationTimeout(timeout)' +excerpt: 'Sets the default navigation timeout in milliseconds.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/setdefaultnavigationtimeout/ +--- + +Sets the default maximum navigation timeout for [Page.goto()](https://playwright.dev/docs/api/class-page#page-goto). + +| Parameter | Type | Default | Description | +|-----------|--------|--------------------------|------------------------------| +| timeout | number | Dependent on the action. | The timeout in milliseconds. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const context = browser.newContext(); + const page = context.newPage(); + context.setDefaultNavigationTimeout(1000); // 1s + + try { + await page.goto('https://httpbin.test.k6.io/delay/5'); + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setDefaultTimeout.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setDefaultTimeout.md new file mode 100644 index 0000000000..11ae7c6dec --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setDefaultTimeout.md @@ -0,0 +1,42 @@ +--- +title: 'setDefaultTimeout(timeout)' +excerpt: 'Sets the default timeout in milliseconds.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/setdefaulttimeout/ +--- + +Sets the default maximum timeout for all methods accepting a `timeout` option in milliseconds. + +| Parameter | Type | Default | Description | +|-----------|--------|--------------------------|------------------------------| +| timeout | number | Dependent on the action. | The timeout in milliseconds. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const context = browser.newContext(); + context.setDefaultTimeout(1000); // 1s + const page = context.newPage(); + await page.click('h2'); // times out +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setGeolocation.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setGeolocation.md new file mode 100644 index 0000000000..929e9e4c06 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setGeolocation.md @@ -0,0 +1,53 @@ +--- +title: 'setGeolocation(geolocation)' +excerpt: "Sets the BrowserContext's geolocation." +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/setgeolocation/ +--- + +
+ +This feature has **known issues**. For details, refer to +[#435](https://github.com/grafana/xk6-browser/issues/435). + +
+ +Sets the context's geolocation. + + + +| Parameter | Type | Default | Description | +|-----------------------|--------|---------|---------------------------------------| +| geolocation | object | `null` | | +| geolocation.latitude | number | `0` | Latitude between -90 and 90. | +| geolocation.longitude | number | `0` | Latitude between -180 and 180. | +| geolocation.accuracy | number | `0` | Optional non-negative accuracy value. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const context = browser.newContext(); + context.setGeolocation({latitude: 59.95, longitude: 30.31667}); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setOffline.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setOffline.md new file mode 100644 index 0000000000..e625c967f2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/setOffline.md @@ -0,0 +1,50 @@ +--- +title: 'setOffline(offline)' +excerpt: "Toggles the BrowserContext's connectivity on/off." +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/setoffline/ +--- + +Toggles the `BrowserContext`'s connectivity on/off. + +| Parameter | Type | Default | Description | +|-----------|---------|---------|---------------------------------------------------------------------------------------------| +| offline | boolean | `false` | Whether to emulate the `BrowserContext` being disconnected (`true`) or connected (`false`). | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const context = browser.newContext(); + + context.setOffline(true); + + const page = context.newPage(); + + try { + // Will not be able to load the page + await page.goto('https://test.k6.io/browser.php'); + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/waitForEvent.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/waitForEvent.md new file mode 100644 index 0000000000..09f16972e2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/02 BrowserContext/waitForEvent.md @@ -0,0 +1,34 @@ +--- +title: 'waitForEvent(event[, optionsOrPredicate])' +excerpt: 'Waits for event to fire and passes its value into the predicate function.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/browsercontext/waitforevent/ +--- + +
+ +This method is a work in progress. +It requires async functionality and returning a `Promise` to be useful in scripts. +Refer to #447 for details. + +Consider using the sync methods `Page.waitForNavigation()` and `Page.waitForSelector()` instead. + +
+ +Waits for the event to fire and passes its value into the predicate function. Returns the event data value when the predicate returns `true`. + + + +| Parameter | Type | Default | Description | +|------------------------------|------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| event | string | `null` | Name of event to wait for. **NOTE**: Currently this argument is disregarded, and `waitForEvent` will always wait for `'close'` or `'page'` events. | +| optionsOrPredicate | function\|object | `null` | Optional. If it's a function, the `'page'` event data will be passed to it and it must return `true` to continue. | +| optionsOrPredicate.predicate | function | `null` | Function that will be called when the `'page'` event is emitted. The event data will be passed to it and it must return `true` to continue. | +| optionsOrPredicate.timeout | number | `30000` | Maximum time to wait in milliseconds. Pass `0` to disable timeout. | + + + +### Returns + +| Type | Description | +| ------ | ------------------------------------------------ | +| object | [Page](/javascript-api/k6-experimental/browser/page/) object | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/03-console-message.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/03-console-message.md new file mode 100644 index 0000000000..b9ed89d940 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/03-console-message.md @@ -0,0 +1,16 @@ +--- +title: "ConsoleMessage" +excerpt: "Browser module: ConsoleMessage Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/consolemessage/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| consoleMessage.args() | - | +| consoleMessage.page() | - | +| consoleMessage.text() | - | +| consoleMessage.type() | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/04-element-handle.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/04-element-handle.md new file mode 100644 index 0000000000..5b68e4f6d2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/04-element-handle.md @@ -0,0 +1,144 @@ +--- +title: "ElementHandle" +excerpt: "Browser module: ElementHandle Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/elementhandle/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| elementHandle.$(selector) | - | +| elementHandle.$$(selector) | - | +| elementHandle.boundingBox() | - | +| elementHandle.check([options]) | - | +| elementHandle.click([options]) | - | +| elementHandle.contentFrame() | - | +| elementHandle.dblclick([options]) | - | +| elementHandle.dispatchEvent(type[, eventInit]) | - | +| elementHandle.fill(value[, options]) | - | +| elementHandle.focus() | - | +| elementHandle.getAttribute() | - | +| elementHandle.hover([options]) | - | +| elementHandle.innerHTML() | - | +| elementHandle.innerText() | - | +| elementHandle.inputValue([options]) | - | +| elementHandle.isChecked() | - | +| elementHandle.isDisabled() | - | +| elementHandle.isEditable() | - | +| elementHandle.isEnabled() | - | +| elementHandle.isHidden() | - | +| elementHandle.isVisible() | - | +| elementHandle.ownerFrame() | - | +| elementHandle.press(key[, options]) | - | +| elementHandle.screenshot([options]) | - | +| elementHandle.scrollIntoViewIfNeeded([options]) | - | +| elementHandle.selectOptions(values[, options]) | - | +| elementHandle.selectText([options]) | - | +| elementHandle.setChecked(checked[, options]) | - | +| elementHandle.tap([options]) | - | +| elementHandle.textContent() | - | +| elementHandle.type(text[, options]) | - | +| elementHandle.uncheck([options]) | - | +| elementHandle.waitForElementState(state[, options]) | - | +| elementHandle.waitForSelector(selector[, options]) | - | + +## Examples + + + +```javascript +import { check } from 'k6'; +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + // Goto front page, find login link and click it + try { + await page.goto('https://test.k6.io/'); + const messagesLink = page.locator('a[href="/my_messages.php"]'); + + await Promise.all([page.waitForNavigation(), messagesLink.click()]); + // Enter login credentials and login + page.locator('input[name="login"]').type('admin'); + page.locator('input[name="password"]').type('123'); + + const submitButton = page.locator('input[type="submit"]'); + + await Promise.all([page.waitForNavigation(), submitButton.click()]); + check(page, { + 'header': p => p.locator('h2').textContent() == 'Welcome, admin!', + }); + } finally { + page.close(); + } +} +``` + + + + + +```javascript +import { browser } from 'k6/experimental/browser'; +import { check } from 'k6'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const page = browser.newPage(); + + // Inject page content + page.setContent(` +
Hello world
+ +
Edit me
+ + + + + `); + + // Check state + check(page, { + visible: (p) => p.$('.visible').isVisible(), + hidden: (p) => p.$('.hidden').isHidden(), + editable: (p) => p.$('.editable').isEditable(), + enabled: (p) => p.$('.enabled').isEnabled(), + disabled: (p) => p.$('.disabled').isDisabled(), + checked: (p) => p.$('.checked').isChecked(), + unchecked: (p) => p.$('.unchecked').isChecked() === false, + }); + + page.close(); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/05-frame.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/05-frame.md new file mode 100644 index 0000000000..93f97e1b93 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/05-frame.md @@ -0,0 +1,57 @@ +--- +title: "Frame" +excerpt: "Browser module: Frame Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/frame/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| frame.$(selector[, options]) | - | +| frame.check(selector[, options]) | - | +| frame.childFrames() | - | +| frame.click(selector[, options]) | - | +| frame.content() | - | +| frame.dblclick(selector[, options]) | - | +| frame.dispatchEvent(selector, type[, eventInit, options]) | - | +| frame.evaluate(pageFunction[, arg]) | - | +| frame.evaluateHandle(pageFunction[, arg]) | - | +| frame.fill(selector, value[, options]) | - | +| frame.focus(selector[, options]) | - | +| frame.frameElement() | - | +| frame.getAttribute(selector, name[, options]) | - | +| frame.goto(url[, options]) | - | +| frame.hover(selector[, options]) | - | +| frame.innerHTML(selector[, options]) | - | +| frame.innerText(selector[, options]) | - | +| frame.inputValue(selector[, options]) | - | +| frame.isChecked(selector[, options]) | - | +| frame.isDetached() | - | +| frame.isDisabled(selector[, options]) | - | +| frame.isEditable(selector[, options]) | - | +| frame.isEnabled(selector[, options]) | - | +| frame.isHidden(selector[, options]) | - | +| frame.isVisible(selector[, options]) | - | +| frame.locator(selector[, options]) | - | +| frame.name() | - | +| frame.page() | - | +| frame.parentFrame() | - | +| frame.press(selector, key[, options]) | - | +| frame.selectOption(selector, values[, options]) | - | +| frame.setChecked(selector, checked[, options]) | - | +| frame.setContent(html[, options]) | - | +| frame.tap(selector[, options]) | - | +| frame.textContent(selector[, options]) | - | +| frame.title() | - | +| frame.title() | - | +| frame.uncheck(selector[, options]) | - | +| frame.url() | - | +| frame.waitForFunction(pageFunction[, arg, options]) | - | +| frame.waitForLoadState([state, options]) | - | +| frame.waitForNavigation([options]) | - | +| frame.waitForSelector(selector[, options]) | - | +| frame.waitForTimeout(timeout) | - | +| frame.waitForURL(url[, options]) | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/06-js-handle.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/06-js-handle.md new file mode 100644 index 0000000000..8934829e9c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/06-js-handle.md @@ -0,0 +1,19 @@ +--- +title: "JSHandle" +excerpt: "Browser module: JSHandle Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/jshandle/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| jsHandle.asElement() | - | +| jsHandle.dispose() | - | +| jsHandle.evaluate(pageFunction[, arg]) | - | +| jsHandle.evaluateHandle(pageFunction[, arg]) | - | +| jsHandle.getProperties() | - | +| jsHandle.getProperty(propertyName) | - | +| jsHandle.jsonValue() | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/07-keyboard.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/07-keyboard.md new file mode 100644 index 0000000000..54579fb415 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/07-keyboard.md @@ -0,0 +1,17 @@ +--- +title: "Keyboard" +excerpt: "Browser module: Keyboard Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/keyboard/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| keyboard.down(key) | - | +| keyboard.insertText(text) | - | +| keyboard.press(key[, options]) | - | +| keyboard.type(text[, options]) | - | +| keyboard.up(key) | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator.md new file mode 100644 index 0000000000..d03400c550 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator.md @@ -0,0 +1,118 @@ +--- +title: "Locator" +excerpt: "Browser module: Locator Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/ +--- + +The Locator API makes it easier to work with dynamically changing elements. Some of the benefits of using it over existing ways to locate an element (e.g. `Page.$()`) include: + +- Helps with writing robust tests by finding an element even if the underlying frame navigates. +- Makes it easier to work with dynamic web pages and SPAs built with Svelte, React, Vue, etc. +- Enables the use of test abstractions like the Page Object Model (POM) pattern to simplify and organize tests. +- `strict` mode is enabled for all `locator` methods, which means that if more than one element matches the given selector it will throw an error. + +Locator can be created with the [page.locator(selector[, options])](/javascript-api/k6-experimental/browser/page/#page-locator) method. + +| Method | Description | +|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| +| [locator.check([options])](/javascript-api/k6-experimental/browser/locator/check) | Select the input checkbox. | +| [locator.click([options])](/javascript-api/k6-experimental/browser/locator/click) | Mouse click on the chosen element. | +| [locator.dblclick([options])](/javascript-api/k6-experimental/browser/locator/dblclick) | Mouse double click on the chosen element. | +| [locator.dispatchEvent(type, eventInit, [options])](/javascript-api/k6-experimental/browser/locator/dispatchevent) | Dispatches HTML DOM event types e.g. `'click'`. | +| [locator.fill(value, [options])](/javascript-api/k6-experimental/browser/locator/fill) | Fill an `input`, `textarea` or `contenteditable` element with the provided value. | +| [locator.focus([options])](/javascript-api/k6-experimental/browser/locator/focus) | Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element, if it can be focused. | +| [locator.getAttribute(name, [options])](/javascript-api/k6-experimental/browser/locator/getattribute) | Returns the element attribute value for the given attribute name. | +| [locator.hover([options])](/javascript-api/k6-experimental/browser/locator/hover) | Hovers over the element. | +| [locator.innerHTML([options])](/javascript-api/k6-experimental/browser/locator/innerhtml) | Returns the `element.innerHTML`. | +| [locator.innerText([options])](/javascript-api/k6-experimental/browser/locator/innertext) | Returns the `element.innerText`. | +| [locator.inputValue([options])](/javascript-api/k6-experimental/browser/locator/inputvalue) | Returns `input.value` for the selected `input`, `textarea` or `select` element. | +| [locator.isChecked([options])](/javascript-api/k6-experimental/browser/locator/ischecked) | Checks if the `checkbox` `input` type is selected. | +| [locator.isDisabled([options])](/javascript-api/k6-experimental/browser/locator/isdisabled) | Checks if the element is `disabled`. | +| [locator.isEditable([options])](/javascript-api/k6-experimental/browser/locator/iseditable) | Checks if the element is `editable`. | +| [locator.isEnabled([options])](/javascript-api/k6-experimental/browser/locator/isenabled) | Checks if the element is `enabled`. | +| [locator.isHidden([options])](/javascript-api/k6-experimental/browser/locator/ishidden) | Checks if the element is `hidden`. | +| [locator.isVisible([options])](/javascript-api/k6-experimental/browser/locator/isvisible) | Checks if the element is `visible`. | +| [locator.press(key, [options])](/javascript-api/k6-experimental/browser/locator/press) | Press a single key on the keyboard or a combination of keys. | +| [locator.selectOption(values, [options])](/javascript-api/k6-experimental/browser/locator/selectoption) | Select one or more options which match the values. | +| [locator.tap([options])](/javascript-api/k6-experimental/browser/locator/tap) | Tap on the chosen element. | +| [locator.textContent([options])](/javascript-api/k6-experimental/browser/locator/textcontent) | Returns the `element.textContent`. | +| [locator.type(text, [options])](/javascript-api/k6-experimental/browser/locator/type) | Type in the text into the input field. | +| [locator.uncheck([options])](/javascript-api/k6-experimental/browser/locator/uncheck) | Unselect the `input` checkbox. | +| [locator.waitFor([options])](/javascript-api/k6-experimental/browser/locator/waitfor) | Wait for the element to be in a particular state e.g. `visible`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + try { + await page.goto("https://test.k6.io/flip_coin.php") + + /* + In this example, we will use two locators, matching a + different betting button on the page. If you were to query + the buttons once and save them as below, you would see an + error after the initial navigation. Try it! + + const heads = page.$("input[value='Bet on heads!']"); + const tails = page.$("input[value='Bet on tails!']"); + + The Locator API allows you to get a fresh element handle each + time you use one of the locator methods. And, you can carry a + locator across frame navigations. Let's create two locators; + each locates a button on the page. + */ + const heads = page.locator("input[value='Bet on heads!']"); + const tails = page.locator("input[value='Bet on tails!']"); + + const currentBet = page.locator("//p[starts-with(text(),'Your bet: ')]"); + + // In the following Promise.all the tails locator clicks + // on the tails button by using the locator's selector. + // Since clicking on each button causes page navigation, + // waitForNavigation is needed -- this is because the page + // won't be ready until the navigation completes. + // Setting up the waitForNavigation first before the click + // is important to avoid race conditions. + await Promise.all([ + page.waitForNavigation(), + tails.click(), + ]); + console.log(currentBet.innerText()); + // the heads locator clicks on the heads button + // by using the locator's selector. + await Promise.all([ + page.waitForNavigation(), + heads.click(), + ]); + console.log(currentBet.innerText()); + await Promise.all([ + page.waitForNavigation(), + tails.click(), + ]); + console.log(currentBet.innerText()); + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/check--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/check--options--.md new file mode 100644 index 0000000000..b77b958db5 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/check--options--.md @@ -0,0 +1,59 @@ +--- +title: 'check([options])' +excerpt: 'Browser module: locator.check method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/check/ +--- + +
+ +This feature has known issues. For details, refer to +[#471](https://github.com/grafana/xk6-browser/issues/471) and [#475](https://github.com/grafana/xk6-browser/issues/475). + +
+ +Use this method to select an `input` checkbox. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const checkbox = page.locator("#checkbox1"); + checkbox.check(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/click--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/click--options--.md new file mode 100644 index 0000000000..2abd3fe85b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/click--options--.md @@ -0,0 +1,95 @@ +--- +title: 'click([options])' +excerpt: 'Browser module: locator.click method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/click/ +--- + +
+ +This method has **known issues**. For details, refer to [#471](https://github.com/grafana/xk6-browser/issues/471) and [#474](https://github.com/grafana/xk6-browser/issues/474). + +
+ +Mouse click on the chosen element. + + + +| Parameter | Type | Default | Description | +|---------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.button | string | `left` | The mouse button (`left`, `middle` or `right`) to use during the action. | +| options.clickCount | number | `1` | The number of times the action is performed. | +| options.delay | number | `0` | Milliseconds to wait between `mousedown` and `mouseup`. | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.modifiers | string[] | `null` | `Alt`, `Control`, `Meta` or `Shift` modifiers keys pressed during the action. If not specified, currently pressed modifiers are used. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Examples + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + const button = page.locator('#counter-button'); + await button.click(); +} +``` + + + +When a click action results in a page navigation, remember to work with `Promise.all()` and `page.waitForNavigation()` to properly handle the asynchronous operation. + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/'); + const messagesLink = page.locator('a[href="/my_messages.php"]'); + + await Promise.all([page.waitForNavigation(), messagesLink.click()]); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/dblclick--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/dblclick--options--.md new file mode 100644 index 0000000000..e04e9d57f8 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/dblclick--options--.md @@ -0,0 +1,62 @@ +--- +title: 'dblclick([options])' +excerpt: 'Browser module: locator.dblclick method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/dblclick/ +--- + +
+ +This feature has known issues. For details, refer to +[#469](https://github.com/grafana/xk6-browser/issues/469) and [#471](https://github.com/grafana/xk6-browser/issues/471). + +
+ +Mouse double click on the chosen element. + + + +| Parameter | Type | Default | Description | +|---------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.button | string | `left` | The mouse button (`left`, `middle` or `right`) to use during the action. | +| options.delay | number | `0` | Milliseconds to wait between `mousedown` and `mouseup`. | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.modifiers | string[] | `null` | `Alt`, `Control`, `Meta` or `Shift` modifiers keys pressed during the action. If not specified, currently pressed modifiers are used. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const button = page.locator("#counter-button"); + button.dblclick(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/dispatchevent--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/dispatchevent--options--.md new file mode 100644 index 0000000000..62582a35f7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/dispatchevent--options--.md @@ -0,0 +1,49 @@ +--- +title: 'dispatchEvent(type, eventInit, [options])' +excerpt: 'Browser module: locator.dispatchEvent method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/dispatchevent/ +--- + +Dispatches HTML DOM event types e.g. `'click'`. + + + +| Parameter | Type | Defaults | Description | +|-----------------|--------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| type | string | `''` | DOM event type e.g. `'click'`. | +| eventInit | object | `null` | Optional event specific properties. See [eventInit](#eventinit) for more details. | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### eventInit + +Since eventInit is event-specific, please refer to the events documentation for the lists of initial properties: + +- [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent) +- [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent) +- [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent) +- [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent) +- [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent) +- [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent) +- [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event) + +### Example + + + +```javascript +import { chromium } from 'k6/experimental/browser'; + +export default async function () { + const browser = chromium.launch(); + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + const button = page.locator("#counter-button"); + button.dispatchEvent('click'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/fill--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/fill--options--.md new file mode 100644 index 0000000000..acb18f00ad --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/fill--options--.md @@ -0,0 +1,49 @@ +--- +title: 'fill(value, [options])' +excerpt: 'Browser module: locator.fill method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/fill/ +--- + +Fill an `input`, `textarea` or `contenteditable` element with the provided value. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| value | string | `''` | Value to set for the `input`, `textarea` or `contenteditable` element. | +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const textbox = page.locator("#text1"); + textbox.fill('hello world!'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/focus--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/focus--options--.md new file mode 100644 index 0000000000..1d506756af --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/focus--options--.md @@ -0,0 +1,46 @@ +--- +title: 'focus([options])' +excerpt: 'Browser module: locator.focus method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/focus/ +--- + +Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element, if it can be focused on. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const textbox = page.locator("#text1"); + textbox.focus(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/getattribute--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/getattribute--options--.md new file mode 100644 index 0000000000..bf6f0af69c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/getattribute--options--.md @@ -0,0 +1,54 @@ +--- +title: 'getAttribute(name, [options])' +excerpt: 'Browser module: locator.getAttribute method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/getattribute/ +--- + +Returns the element attribute value for the given attribute name. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | `''` | Attribute name to get the value for. | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|--------|-------------------------------------| +| string | The value of the attribute or null. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const textbox = page.locator("#text1"); + const attribute = textbox.getAttribute('onfocus'); + console.log(attribute); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/hover--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/hover--options--.md new file mode 100644 index 0000000000..1047ed8873 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/hover--options--.md @@ -0,0 +1,60 @@ +--- +title: 'hover([options])' +excerpt: 'Browser module: locator.hover method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/hover/ +--- + +
+ +This feature has known issues. For details, refer to +[#471](https://github.com/grafana/xk6-browser/issues/471). + +
+ +Hovers over the element. + + + +| Parameter | Type | Default | Description | +|---------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.modifiers | string[] | `null` | `Alt`, `Control`, `Meta` or `Shift` modifiers keys pressed during the action. If not specified, currently pressed modifiers are used. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const offScreenElement = page.locator("#off-screen"); + offScreenElement.hover(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/innerhtml--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/innerhtml--options--.md new file mode 100644 index 0000000000..439fb1d090 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/innerhtml--options--.md @@ -0,0 +1,53 @@ +--- +title: 'innerHTML([options])' +excerpt: 'Browser module: locator.innerHTML method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/innerhtml/ +--- + +Returns the `element.innerHTML`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|--------|--------------------------------| +| string | The innerHTML of the element. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const offScreen = page.locator('#off-screen'); + const innerHTML = offScreen.innerHTML(); + console.log(innerHTML); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/innertext--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/innertext--options--.md new file mode 100644 index 0000000000..62d5a3fa25 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/innertext--options--.md @@ -0,0 +1,53 @@ +--- +title: 'innerText([options])' +excerpt: 'Browser module: locator.innerText method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/innertext/ +--- + +Returns the `element.innerText`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|--------|--------------------------------| +| string | The innerText of the element. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const offScreen = page.locator('#off-screen'); + const innerText = offScreen.innerText(); + console.log(innerText); // Off page div +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/inputvalue--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/inputvalue--options--.md new file mode 100644 index 0000000000..f703b445b9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/inputvalue--options--.md @@ -0,0 +1,54 @@ +--- +title: 'inputValue([options])' +excerpt: 'Browser module: locator.inputValue method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/inputvalue/ +--- + +Returns `input.value` for the selected `input`, `textarea` or `select` element. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|--------|----------------------------------| +| string | The input value of the element. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const textInput = page.locator('#text1'); + textInput.fill("Hello world!"); + const inputValue = textInput.inputValue(); + console.log(inputValue); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/ischecked--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/ischecked--options--.md new file mode 100644 index 0000000000..8923d1fae0 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/ischecked--options--.md @@ -0,0 +1,54 @@ +--- +title: 'isChecked([options])' +excerpt: 'Browser module: locator.isChecked method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/ischecked/ +--- + +Checks to see if the `checkbox` `input` type is selected or not. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|------|---------------------------------------------------| +| bool | `true` if the checkbox is selected, else `false`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const checkbox = page.locator('#checkbox1'); + if (!checkbox.isChecked()) { + checkbox.check(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isdisabled--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isdisabled--options--.md new file mode 100644 index 0000000000..9784390496 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isdisabled--options--.md @@ -0,0 +1,54 @@ +--- +title: 'isDisabled([options])' +excerpt: 'Browser module: locator.isDisabled method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/isdisabled/ +--- + +Checks if the element is `disabled`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|------|---------------------------------------------------| +| bool | `true` if the element is `disabled`, else `false`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#input-text-disabled'); + if (text.isDisabled()) { + console.log("element is disabled") + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/iseditable--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/iseditable--options--.md new file mode 100644 index 0000000000..2a183a61bf --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/iseditable--options--.md @@ -0,0 +1,54 @@ +--- +title: 'isEditable([options])' +excerpt: 'Browser module: locator.isEditable method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/iseditable/ +--- + +Checks if the element is `editable`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|------|----------------------------------------------------| +| bool | `true` if the element is `editable`, else `false`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#text1'); + if (text.isEditable()) { + text.fill("hello world!"); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isenabled--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isenabled--options--.md new file mode 100644 index 0000000000..f65c521333 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isenabled--options--.md @@ -0,0 +1,55 @@ +--- +title: 'isEnabled([options])' +excerpt: 'Browser module: locator.isEnabled method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/isenabled/ +--- + +Checks if the element is `enabled`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|------|---------------------------------------------------| +| bool | `true` if the element is `enabled`, else `false`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#text1'); + if (text.isEnabled()) { + console.log("element is enabled"); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/ishidden--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/ishidden--options--.md new file mode 100644 index 0000000000..9e9fd57ac9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/ishidden--options--.md @@ -0,0 +1,54 @@ +--- +title: 'isHidden([options])' +excerpt: 'Browser module: locator.isHidden method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/ishidden/ +--- + +Checks if the element is `hidden`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|------|---------------------------------------------------| +| bool | `true` if the element is `hidden`, else `false`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#input-text-hidden'); + if (text.isHidden()) { + console.log("element is hidden"); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isvisible--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isvisible--options--.md new file mode 100644 index 0000000000..50cb674a4b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/isvisible--options--.md @@ -0,0 +1,54 @@ +--- +title: 'isVisible([options])' +excerpt: 'Browser module: locator.isVisible method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/isvisible/ +--- + +Checks if the element is `visible`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|------|---------------------------------------------------| +| bool | `true` if the element is `visible`, else `false`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#text1'); + if (text.isVisible()) { + console.log("element is visible"); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/press--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/press--options--.md new file mode 100644 index 0000000000..3b072072ad --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/press--options--.md @@ -0,0 +1,51 @@ +--- +title: 'press(key, [options])' +excerpt: 'Browser module: locator.press method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/press/ +--- + +Press a single key on the keyboard or a combination of keys. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| key | string | `''` | Name of the key to press or a character to generate, such as `ArrowLeft` or `a`. A superset of the key values can be found [here](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values). | +| options | object | `null` | | +| options.delay | number | `0` | Milliseconds to wait between `keydown` and `keyup`. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#text1'); + text.press('i'); + text.press('ArrowLeft'); + text.press('h'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/selectoption--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/selectoption--options--.md new file mode 100644 index 0000000000..b1b29f0841 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/selectoption--options--.md @@ -0,0 +1,62 @@ +--- +title: 'selectOption(values, [options])' +excerpt: 'Browser module: locator.selectOption method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/selectoption/ +--- + +
+ +This feature has **known issues**. For details, refer to +[#470](https://github.com/grafana/xk6-browser/issues/470) and [#471](https://github.com/grafana/xk6-browser/issues/471). + +
+ +Select one or more options which match the values. + + + +| Parameter | Type | Default | Description | +|---------------------|------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| values | string or string[] or object | `''` | If the `select` has the multiple attribute, all matching options are selected, otherwise only the first option matching one of the passed options is selected. Object can be made up of keys with `value`, `label` or `index`. | +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|----------|-------------------------------| +| string[] | List of the selected options. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const options = page.locator('#numbers-options'); + options.selectOption('three'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/tap--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/tap--options--.md new file mode 100644 index 0000000000..608e45cbf9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/tap--options--.md @@ -0,0 +1,50 @@ +--- +title: 'tap([options])' +excerpt: 'Browser module: locator.tap method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/tap/ +--- + +
+ +This feature has **known issues**. For details, refer to +[#436](https://github.com/grafana/xk6-browser/issues/436) and [#471](https://github.com/grafana/xk6-browser/issues/471). + +
+ +Tap on the chosen element. + + + +| Parameter | Type | Default | Description | +|---------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.modifiers | string[] | `null` | `Alt`, `Control`, `Meta` or `Shift` modifiers keys pressed during the action. If not specified, currently pressed modifiers are used. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export default async function () { + const page = browser.newPage({ + hasTouch: true, + }); + + await page.goto('https://test.k6.io/browser.php'); + const options = page.locator("#numbers-options"); + options.tap(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/textcontent--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/textcontent--options--.md new file mode 100644 index 0000000000..686688c892 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/textcontent--options--.md @@ -0,0 +1,52 @@ +--- +title: 'textContent([options])' +excerpt: 'Browser module: locator.textContent method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/textcontent/ +--- + +Returns the `element.textContent`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|--------|-------------------------------------------| +| string | The text content of the selector or null. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const options = page.locator("#checkbox1"); + console.log(options.textContent()); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/type--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/type--options--.md new file mode 100644 index 0000000000..4d69ef2ba6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/type--options--.md @@ -0,0 +1,49 @@ +--- +title: 'type(text, [options])' +excerpt: 'Browser module: locator.type method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/type/ +--- + +Type in the text into the input field. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| text | string | `''` | A text to type into a focused element. | +| options | object | `null` | | +| options.delay | number | `0` | Milliseconds to wait between key presses. Defaults to `0`. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator("#text1"); + text.type('hello world!'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/uncheck--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/uncheck--options--.md new file mode 100644 index 0000000000..1bafa3614b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/uncheck--options--.md @@ -0,0 +1,60 @@ +--- +title: 'uncheck([options])' +excerpt: 'Browser module: locator.uncheck method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/uncheck/ +--- + +
+ +This feature has **known issues**. +For details, refer to [#471](https://github.com/grafana/xk6-browser/issues/471). + +
+ +Unselect the `input` checkbox. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + const checkbox = page.locator("#checkbox1"); + checkbox.check(); + checkbox.uncheck(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/waitfor--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/waitfor--options--.md new file mode 100644 index 0000000000..f740d9d68b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/08 Locator/waitfor--options--.md @@ -0,0 +1,57 @@ +--- +title: 'waitFor([options])' +excerpt: 'Browser module: locator.waitFor method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/waitfor/ +--- + +
+ +This feature has **known issues**. For details, +refer to [#472](https://github.com/grafana/xk6-browser/issues/472). + +
+ +Wait for the element to be in a particular state e.g. `visible`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.state | string | `visible` | Can be `attached`, `detached`, `visible` or `hidden`. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + const text = page.locator('#input-text-hidden'); + text.waitFor({ + state: 'hidden', + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/09-mouse.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/09-mouse.md new file mode 100644 index 0000000000..1e970fcb7a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/09-mouse.md @@ -0,0 +1,18 @@ +--- +title: "Mouse" +excerpt: "Browser module: Mouse Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/mouse/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| mouse.click(x, y[, options]) | - | +| mouse.dblclick(x, y[, options]) | - | +| mouse.down([options]) | - | +| mouse.move(x, y[, options]) | - | +| mouse.up([options]) | - | +| mouse.wheel(deltaX, deltaY) | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page.md new file mode 100644 index 0000000000..84822529c3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page.md @@ -0,0 +1,69 @@ +--- +title: "Page" +excerpt: "Browser module: Page Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/ +--- + +Page provides methods to interact with a single tab in a running web browser. A single [BrowserContext](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/) can have many `pages`. + +| Method | Description | +|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| +| [page.bringToFront()](/javascript-api/k6-experimental/browser/page/bringtofront/) | Activates a browser tab. | +| [page.check(selector[, options])](/javascript-api/k6-experimental/browser/page/check/) | Select the input checkbox. | +| [page.click(selector[, options])](/javascript-api/k6-experimental/browser/page/click/) | Clicks on an element matching a `selector`. | +| [page.close()](/javascript-api/k6-experimental/browser/page/close/) | Closes a tab that the `page` is associated with. | +| [page.content()](/javascript-api/k6-experimental/browser/page/content/) | Gets the HTML contents of the page. | +| [page.context()](/javascript-api/k6-experimental/browser/page/context/) | Gets the [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) that the page belongs to. | +| [page.dblclick(selector[, options])](/javascript-api/k6-experimental/browser/page/dblclick/) | With the [Mouse](/javascript-api/k6-experimental/browser/mouse/), double click on an element matching the provided `selector`. | +| [page.dispatchEvent(selector, type, eventInit[, options])](/javascript-api/k6-experimental/browser/page/dispatchevent/) | Dispatches HTML DOM event types e.g. `'click'` | +| [page.$(selector)](/javascript-api/k6-experimental/browser/page/page-$/) | Finds an element matching the specified `selector` within the page. | +| [page.$$(selector)](/javascript-api/k6-experimental/browser/page/page-$$/) | Finds all elements matching the specified `selector` within the page. | +| [page.emulateMedia([options])](/javascript-api/k6-experimental/browser/page/emulatemedia/) | Changes the CSS media type and the color scheme feature. | +| [page.emulateVisionDeficiency(type)](/javascript-api/k6-experimental/browser/page/emulatevisiondeficiency/) | Emulates your website with the specified vision deficiency `type`. | +| [page.evaluate(pageFunction[, arg])](/javascript-api/k6-experimental/browser/page/evaluate/) | Returns the value of the `pageFunction` invocation. | +| [page.evaluateHandle(pageFunction[, arg])](/javascript-api/k6-experimental/browser/page/evaluate/) | Returns the value of the `pageFunction` invocation as a [JSHandle](/javascript-api/k6-experimental/browser/jshandle/). | +| [page.fill(selector, value[, options])](/javascript-api/k6-experimental/browser/page/fill/) | Fill an `input`, `textarea` or `contenteditable` element with the provided value. | +| [page.focus(selector[, options])](/javascript-api/k6-experimental/browser/page/focus/) | Fetches an element with `selector` and focuses on it. | +| [page.frames()](/javascript-api/k6-experimental/browser/page/frames/) | Returns an array of frames on the page. | +| [page.getAttribute(selector, name[, options])](/javascript-api/k6-experimental/browser/page/getattribute/) | Returns the element attribute value for the given attribute name. | +| [page.goto(url[, options])](/javascript-api/k6-experimental/browser/page/goto/) | Navigates to the specified `url`. | +| [page.hover(selector[, options])](/javascript-api/k6-experimental/browser/page/hover/) | Hovers over an element matching `selector`. | +| [page.innerHTML(selector[, options])](/javascript-api/k6-experimental/browser/page/innerhtml/) | Returns the `element.innerHTML`. | +| [page.innerText(selector[, options])](/javascript-api/k6-experimental/browser/page/innertext/) | Returns the `element.innerText`. | +| [page.inputValue(selector[, options])](/javascript-api/k6-experimental/browser/page/inputvalue/) | Returns `input.value` for the selected `input`, `textarea` or `select` element. | +| [page.isChecked(selector[, options])](/javascript-api/k6-experimental/browser/page/ischecked/) | Checks to see if the `checkbox` `input` type is selected or not. | +| [page.isClosed()](/javascript-api/k6-experimental/browser/page/isclosed/) | Checks if the page has been closed. | +| [page.isDisabled(selector[, options])](/javascript-api/k6-experimental/browser/page/isdisabled/) | Checks if the element is `disabled`. | +| [page.isEditable(selector[, options])](/javascript-api/k6-experimental/browser/page/iseditable/) | Checks if the element is `editable`. | +| [page.isEnabled(selector[, options])](/javascript-api/k6-experimental/browser/page/isenabled/) | Checks if the element is `enabled`. | +| [page.isHidden(selector[, options])](/javascript-api/k6-experimental/browser/page/ishidden/) | Checks if the element is `hidden`. | +| [page.isVisible(selector[, options])](/javascript-api/k6-experimental/browser/page/isvisible/) | Checks if the element is `visible`. | +| [page.keyboard](/javascript-api/k6-experimental/browser/page/keyboard/) | Returns the [Keyboard](/javascript-api/k6-experimental/browser/keyboard/) instance to interact with a virtual keyboard on the page. | +| [page.locator(selector)](/javascript-api/k6-experimental/browser/page/locator/) | Returns a [Locator](/javascript-api/k6-experimental/browser/locator/) for the given `selector`. | +| [page.mainFrame()](/javascript-api/k6-experimental/browser/page/mainframe/) | Returns the page's main [Frame](/javascript-api/k6-experimental/browser/frame/). | +| [page.mouse](/javascript-api/k6-experimental/browser/page/mouse/) | Returns the [Mouse](/javascript-api/k6-experimental/browser/mouse/) instance to interact with a virtual mouse on the page. | +| [page.on(event, handler)](/javascript-api/k6-experimental/browser/page/on/) | Registers a handler to be called whenever the specified event occurs. | +| [page.opener()](/javascript-api/k6-experimental/browser/page/opener/) | Returns the `page` that opened the current `page`. | +| [page.press(selector, key[, options])](/javascript-api/k6-experimental/browser/page/press/) | Focuses the element, and then presses the given `key` on the [Keyboard](/javascript-api/k6-experimental/browser/keyboard/). | +| [page.reload([options])](/javascript-api/k6-experimental/browser/page/reload/) | Reloads the current page. | +| [page.screenshot([options])](/javascript-api/k6-experimental/browser/page/screenshot/) | Returns a buffer with the captured screenshot from the web browser. | +| [page.selectOption(selector, values[, options])](/javascript-api/k6-experimental/browser/page/selectoption/) | Selects one or more options which match the values from a `` element. + + + +| Parameter | Type | Default | Description | +|---------------------|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| selector | string | `''` | A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. | +| values | string or string[] or object | `''` | If the `select` has the multiple attribute, all matching options are selected, otherwise only the first option matching one of the passed options is selected. Object can be made up of keys with `value`, `label` or `index`. | +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.strict | boolean| `false` | When `true`, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|----------|-------------------------------| +| string[] | List of the selected options. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + page.selectOption('#numbers-options', 'three'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setcontent--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setcontent--options--.md new file mode 100644 index 0000000000..1f6d98bc7c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setcontent--options--.md @@ -0,0 +1,55 @@ +--- +title: 'setContent(html[, options])' +excerpt: 'Browser module: page.setContent(html[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/setcontent/ +--- + +Sets the supplied HTML string to the current page. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| html | string | `''` | HTML markup to assign to the page. +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum operation time in milliseconds. Pass `0` to disable the timeout. The default value can be changed via the [browserContext.setDefaultNavigationTimeout(timeout)](/javascript-api/k6-experimental/browser/browsercontext/setdefaultnavigationtimeout/), [browserContext.setDefaultTimeout(timeout)](/javascript-api/k6-experimental/browser/browsercontext/setdefaulttimeout/), [page.setDefaultNavigationTimeout(timeout)](/javascript-api/k6-experimental/browser/page/setdefaultnavigationtimeout/) or [page.setDefaultTimeout(timeout)](/javascript-api/k6-experimental/browser/page/setdefaulttimeout/) methods. Setting the value to `0` will disable the timeout. | +| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + const htmlContent = ` + + + Test + Test + + `; + + page.setContent(htmlContent); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setdefaultnavigationtimeout.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setdefaultnavigationtimeout.md new file mode 100644 index 0000000000..b120e6dbf6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setdefaultnavigationtimeout.md @@ -0,0 +1,46 @@ +--- +title: 'setDefaultNavigationTimeout(timeout)' +excerpt: 'Browser module: page.setDefaultNavigationTimeout(timeout) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/setdefaultnavigationtimeout/ +--- + +This setting will change the navigation timeout for the following methods: + - [page.goto(url, [options])](/javascript-api/k6-experimental/browser/page/goto/) + - [page.reload([options])](/javascript-api/k6-experimental/browser/page/reload/) + - [page.setContent(html, [options])](/javascript-api/k6-experimental/browser/page/setcontent/) + - [page.waitForNavigation([options])](/javascript-api/k6-experimental/browser/page/waitfornavigation/) + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| timeout | number | | Timeout in milliseconds. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + page.setDefaultNavigationTimeout(60000); + await page.goto('https://test.k6.io/browser.php'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setdefaulttimeout.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setdefaulttimeout.md new file mode 100644 index 0000000000..827e456c08 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setdefaulttimeout.md @@ -0,0 +1,42 @@ +--- +title: 'setDefaultTimeout(timeout)' +excerpt: 'Browser module: page.setDefaultTimeout(timeout) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/setdefaulttimeout/ +--- + +This setting will change the timeout for all the methods accepting a `timeout` option. + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| timeout | number | | Timeout in milliseconds. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + page.setDefaultTimeout(60000); + await page.goto('https://test.k6.io/browser.php'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setextrahttpheaders--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setextrahttpheaders--options--.md new file mode 100644 index 0000000000..d2548e6482 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setextrahttpheaders--options--.md @@ -0,0 +1,43 @@ +--- +title: 'setExtraHTTPHeaders(headers)' +excerpt: 'Browser module: page.setExtraHTTPHeaders(headers) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/setextrahttpheaders/ +--- + +This sets extra HTTP headers which will be sent with subsequent HTTP requests. + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| headers | Object | | An object containing the additional HTTP headers. All header values must be strings. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + page.setExtraHTTPHeaders({ 'foo': 'bar' }); + const url = await page.goto('https://test.k6.io/browser.php'); + + console.log(url.request().headers().foo) // prints bar +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setviewportsize.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setviewportsize.md new file mode 100644 index 0000000000..32d080454d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/setviewportsize.md @@ -0,0 +1,50 @@ +--- +title: 'setViewportSize(viewportSize)' +excerpt: 'Browser module: page.setViewportSize(viewportSize) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/setviewportsize/ +--- + +This will update the page's width and height. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| viewportSize | Object | | An object containing the additional HTTP headers. All header values must be strings. | +| viewportSize.width | number | | Page width in pixels. | +| viewportSize.height | number | | Page height in pixels. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + page.setViewportSize({ + width: 640, + height: 480, + }); + await page.goto('https://test.k6.io/browser.php'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/tap--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/tap--options--.md new file mode 100644 index 0000000000..fe822e811f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/tap--options--.md @@ -0,0 +1,61 @@ +--- +title: 'tap(selector[, options])' +excerpt: 'Browser module: locator.tap(selector[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/tap/ +--- + +
+ +Use locator-based [`locator.tap([options])`](/javascript-api/k6-experimental/browser/locator/tap/) instead. + +
+ +Tap the first element that matches the selector. + + + +| Parameter | Type | Default | Description | +|---------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| selector | string | `''` | A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. | +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.modifiers | string[] | `null` | `Alt`, `Control`, `Meta` or `Shift` modifiers keys pressed during the action. If not specified, currently pressed modifiers are used. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.strict | boolean| `false` | When `true`, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + page.tap('#numbers-options'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/textcontent--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/textcontent--options--.md new file mode 100644 index 0000000000..f56fc261d9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/textcontent--options--.md @@ -0,0 +1,60 @@ +--- +title: 'textContent(selector[, options])' +excerpt: 'Browser module: locator.textContent(selector[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/textcontent/ +--- + +
+ +Use locator-based [`locator.textContent([options])`](/javascript-api/k6-experimental/browser/locator/textcontent/) instead. + +
+ +Returns the `element.textContent`. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| selector | string | `''` | A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. | +| options | object | `null` | | +| options.strict | boolean| `false` | When `true`, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +|--------|-------------------------------------------| +| string | The text content of the selector or null. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + console.log(page.textContent('#checkbox1')); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/title.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/title.md new file mode 100644 index 0000000000..dec0830453 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/title.md @@ -0,0 +1,43 @@ +--- +title: 'title()' +excerpt: 'Browser module: page.title method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/title/ +--- + +Returns the page's title. + +### Returns + +| Type | Description | +|------|---------------------------------------------------| +| string | The page's title. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + console.log(page.title()); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/touchscreen.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/touchscreen.md new file mode 100644 index 0000000000..23dd1c39b4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/touchscreen.md @@ -0,0 +1,43 @@ +--- +title: 'touchScreen' +excerpt: 'Browser module: page.touchScreen method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/touchscreen/ +--- + +Returns the [Touchscreen](/javascript-api/k6-experimental/browser/touchscreen/) instance to interact with a virtual touchscreen on the page. + +### Returns + +| Type | Description | +| ---- | ----------- | +| [Touchscreen](/javascript-api/k6-experimental/browser/touchscreen/) | The `Touchscreen` instance associated with the page. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + page.touchScreen.tap(50, 50); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/type--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/type--options--.md new file mode 100644 index 0000000000..6d8cb2630f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/type--options--.md @@ -0,0 +1,57 @@ +--- +title: 'type(selector, text[, options])' +excerpt: 'Browser module: page.type(selector, text[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/type/ +--- + +
+ +Use locator-based [`locator.type()`](/javascript-api/k6-experimental/browser/locator/type/) instead. + +
+ +Type the `text` in the first element found that matches the selector. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| selector | string | `''` | A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. | +| text | string | `''` | A text to type into a focused element. | +| options | object | `null` | | +| options.delay | number | `0` | Milliseconds to wait between key presses. Defaults to `0`. | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.strict | boolean| `false` | When `true`, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + page.type('#text1', 'hello world!'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/uncheck--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/uncheck--options--.md new file mode 100644 index 0000000000..3ba417e69f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/uncheck--options--.md @@ -0,0 +1,61 @@ +--- +title: 'uncheck(selector[, options])' +excerpt: 'Browser module: page.uncheck(selector[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/uncheck/ +--- + +
+ +Use locator-based [`locator.uncheck([options])`](/javascript-api/k6-experimental/browser/locator/uncheck/) instead. + +
+ +This method is used to unselect an input checkbox. + + + +| Parameter | Type | Default | Description | +|---------------------|---------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| selector | string | `''` | A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. | +| options | object | `null` | | +| options.force | boolean | `false` | Setting this to `true` will bypass the actionability checks (`visible`, `stable`, `enabled`). | +| options.noWaitAfter | boolean | `false` | If set to `true` and a navigation occurs from performing this action, it will not wait for it to complete. | +| options.position | object | `null` | A point to use relative to the top left corner of the element. If not supplied, a visible point of the element is used. | +| options.position.x | number | `0` | The x coordinate. | +| options.position.y | number | `0` | The y coordinate. | +| options.strict | boolean| `false` | When `true`, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.trial | boolean | `false` | Setting this to `true` will perform the actionability checks without performing the action. | + + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + page.check('#checkbox1'); + page.uncheck('#checkbox1'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/url.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/url.md new file mode 100644 index 0000000000..a2348bd915 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/url.md @@ -0,0 +1,43 @@ +--- +title: 'url()' +excerpt: 'Browser module: page.url method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/url/ +--- + +Returns the page's URL. + +### Returns + +| Type | Description | +| ---- | ----------- | +| string | The page's URL. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + console.log(page.url()); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/viewportsize.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/viewportsize.md new file mode 100644 index 0000000000..09bfd752e6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/viewportsize.md @@ -0,0 +1,48 @@ +--- +title: 'viewportSize()' +excerpt: 'Browser module: page.viewportSize method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/viewportsize/ +--- + +Returns the page's size (width and height). + +### Returns + +| Type | Description | +| ---- | ----------- | +| Object | An object containing the page's width and height. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + page.setViewportSize({ + width: 640, + height: 480, + }); + await page.goto('https://test.k6.io/browser.php'); + + console.log(page.viewportSize()); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforfunction--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforfunction--options--.md new file mode 100644 index 0000000000..49e63a37cd --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforfunction--options--.md @@ -0,0 +1,73 @@ +--- +title: 'waitForFunction(pageFunction, arg[, options])' +excerpt: 'Browser module: page.waitForFunction(pageFunction, arg[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforfunction/ +--- + +Returns when the `pageFunction` returns a truthy value. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| pageFunction | function | | Function to be evaluated in the page context. | +| arg | string | `''` | Optional argument to pass to `pageFunction` | +| options | object | `null` | | +| options.polling | number or `raf` | `raf` | If `polling` is `'raf'`, then `pageFunction` is constantly executed in `requestAnimationFrame` callback. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Returns + +| Type | Description | +| ---- | ----------- | +| Promise<[JSHandle](/javascript-api/k6-experimental/browser/jshandle/)> | The `JSHandle` instance associated with the page. | + +### Example + + + + + +```javascript +import { browser } from 'k6/experimental/browser'; +import { check } from 'k6'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + try { + page.evaluate(() => { + setTimeout(() => { + const el = document.createElement('h1'); + el.innerHTML = 'Hello'; + document.body.appendChild(el); + }, 1000); + }); + + const ok = await page.waitForFunction("document.querySelector('h1')", { + polling: 'mutation', + timeout: 2000, + }); + check(ok, { 'waitForFunction successfully resolved': ok.innerHTML() == 'Hello' }); + } finally { + page.close(); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforloadstate--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforloadstate--options--.md new file mode 100644 index 0000000000..c49581a5ff --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforloadstate--options--.md @@ -0,0 +1,83 @@ +--- +title: 'waitForLoadState(state[, options])' +excerpt: 'Browser module: page.waitForLoadState(state[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforloadstate/ +--- + +
+ +This method has **known issues**. For details, refer to [#880](https://github.com/grafana/xk6-browser/issues/880). + +
+ +This waits for the given load state to be reached. It will immediately unblock if that lifecycle event has already been received. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| state | string | `load` | Optional load state to wait for. See [Events](#events) for more details. | +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Events + +
+ + `networkidle` is DISCOURAGED. Don't use this method for testing especially with chatty websites where the event may never fire, rely on web assertions to assess readiness instead. + +
+ +Events can be either: + +- `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. +- `'load'` - consider operation to be finished when the `load` event is fired. +- `'networkidle'` - Consider operation to be finished when there are no network connections for at least `500` ms. + +### Example + + + +```javascript +import { check } from 'k6'; +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + try { + await page.goto('https://test.k6.io/my_messages.php'); + + page.locator('input[name="login"]').type('admin'); + page.locator('input[name="password"]').type('123'); + + const submitButton = page.locator('input[type="submit"]'); + await submitButton.click(); + + page.waitForLoadState(); // waits for the default `load` event + + check(page, { + 'header': p => p.locator('h2').textContent() == 'Welcome, admin!', + }); + } finally { + page.close(); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitfornavigation--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitfornavigation--options--.md new file mode 100644 index 0000000000..da0794f205 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitfornavigation--options--.md @@ -0,0 +1,83 @@ +--- +title: 'waitForNavigation([options])' +excerpt: 'Browser module: page.waitForNavigation([options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitfornavigation/ +--- + +Waits for the given navigation lifecycle event to occur and returns the main resource response. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | +| options.waitUntil | string | `load` | When to consider operation to have succeeded. See [Events](#events) for more details. | + + + + +### Events + +
+ + `networkidle` is DISCOURAGED. Don't use this method for testing especially with chatty websites where the event may never fire, rely on web assertions to assess readiness instead. + +
+ +Events can be either: + +- `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired. +- `'load'` - consider operation to be finished when the `load` event is fired. +- `'networkidle'` - Consider operation to be finished when there are no network connections for at least `500` ms. + +### Returns + +| Type | Description | +| ---- | ----------- | +| Promise | The `Response` instance associated with the page. Else, it returns `null` | + +### Example + + + +```javascript +import { check } from 'k6'; +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + try { + await page.goto('https://test.k6.io/my_messages.php'); + + page.locator('input[name="login"]').type('admin'); + page.locator('input[name="password"]').type('123'); + + const submitButton = page.locator('input[type="submit"]'); + + await Promise.all([page.waitForNavigation(), submitButton.click()]) + + check(page, { + 'header': p => p.locator('h2').textContent() == 'Welcome, admin!', + }); + } finally { + page.close(); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforselector--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforselector--options--.md new file mode 100644 index 0000000000..3667ba4dec --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitforselector--options--.md @@ -0,0 +1,69 @@ +--- +title: 'waitForSelector(selector[, options])' +excerpt: 'Browser module: page.waitForSelector(selector[, options]) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforselector/ +--- + +
+ +Use web assertions that assert visibility or a locator-based [`locator.waitFor([options])`](/javascript-api/k6-experimental/browser/locator/waitfor/) instead. + +
+ +Returns when element specified by selector satisfies `state` option. + + + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| selector | string | `''` | A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. | +| options | object | `null` | | +| options.state | string | `visible` | Can be either `attached`, `detached`, `visible`, `hidden` See [Element states](#element-states) for more details. | +| options.strict | boolean| `false` | When `true`, the call requires selector to resolve to a single element. If given selector resolves to more than one element, the call throws an exception. | +| options.timeout | number | `30000` | Maximum time in milliseconds. Pass `0` to disable the timeout. Default is overridden by the `setDefaultTimeout` option on [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) or [Page](/javascript-api/k6-experimental/browser/page/). | + + + +### Element states + +Element states can be either: + +- `'attached'` - wait for element to be present in DOM. +- `'detached'` - wait for element to not be present in DOM. +- `'visible'` - wait for element to have non-empty bounding box and no `visibility:hidden`. +- `'hidden'` - wait for element to be either detached from DOM, or have an empty bounding box or `visibility:hidden`. + +### Returns + +| Type | Description | +| ---- | ----------- | +| null \| [ElementHandle](/javascript-api/k6-experimental/browser/keyboard/) | `ElementHandle` when a matching element is found. Else, it returns `null`. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + await page.goto('https://test.k6.io/browser.php'); + page.waitForSelector('#text1'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitfortimeout--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitfortimeout--options--.md new file mode 100644 index 0000000000..1a2671bf3c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/waitfortimeout--options--.md @@ -0,0 +1,47 @@ +--- +title: 'waitForTimeout(timeout)' +excerpt: 'Browser module: waitForTimeout(timeout) method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitfortimeout/ +--- + +
+ +Never wait for timeout in production, use this only for debugging. Tests that wait for time are inherently flaky. Use [`Locator`](/javascript-api/k6-experimental/browser/locator/) actions and web assertions that wait automatically. + +
+ +Waits for the given `timeout` in milliseconds. + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| timeout | number | | Timeout in milliseconds. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + page.waitForTimeout(5000); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/workers.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/workers.md new file mode 100644 index 0000000000..1ce5df781f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/10 Page/workers.md @@ -0,0 +1,43 @@ +--- +title: 'workers()' +excerpt: 'Browser module: page.workers method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/workers/ +--- + +This method returns an array of the dedicated [WebWorkers](/javascript-api/k6-experimental/browser/worker/) associated with the page. + +### Returns + +| Type | Description | +| ---- | ----------- | +| [WebWorkers](/javascript-api/k6-experimental/browser/worker/)[] | Array of `WebWorkers` associated with the page. | + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage(); + + await page.goto('https://test.k6.io/browser.php'); + console.log(page.workers()); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/11 Request.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/11 Request.md new file mode 100644 index 0000000000..1f562a433b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/11 Request.md @@ -0,0 +1,28 @@ +--- +title: "Request" +excerpt: "Browser module: Request Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/request/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| request.allHeaders() | - | +| request.frame() | - | +| request.headers() | - | +| request.headersArray() | - | +| request.headerValue(name) | - | +| request.isNavigationRequest() | - | +| request.method() | - | +| request.postData() | - | +| request.postDataBuffer() | - | +| request.redirectedFrom() | - | +| request.redirectedTo() | - | +| request.resourceType() | - | +| request.response() | - | +| [request.size()](/javascript-api/k6-experimental/browser/request/size) | Unlike Playwright, this method returns an object containing the sizes of request headers and body. | +| request.timing() | - | +| request.url() | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/11 Request/size.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/11 Request/size.md new file mode 100644 index 0000000000..d643d6beed --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/11 Request/size.md @@ -0,0 +1,13 @@ +--- +title: 'size()' +excerpt: 'Browser module: Request.size method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/request/size/ +--- + +Similar to Playwright's [`request.sizes()`](https://playwright.dev/docs/api/class-request#request-sizes), this method returns the size (in bytes) of body and header sections of the [Request](/javascript-api/k6-experimental/browser/request). + +### Returns + +| Type | Description | +|--------|---------------------------------------| +| object | `{ body: , headers: }` | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/12-response.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/12-response.md new file mode 100644 index 0000000000..23ea45cb40 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/12-response.md @@ -0,0 +1,28 @@ +--- +title: "Response" +excerpt: "Browser module: Response Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/response/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | Description | +| - | - | - | +| response.allHeaders() | - | - | +| response.body() | - | - | +| response.frame() | - | - | +| response.headers() | - | - | +| response.headersArray() | - | - | +| response.headerValue(name) | - | - | +| response.headerValues(name) | - | - | +| response.json() | - | - | +| response.ok() | - | - | +| response.request() | - | - | +| response.securityDetails() | - | - | +| response.serverAddr() | - | - | +| response.status() | - | - | +| response.statusText() | - | - | +| response.size() | - | Similar to [`Request.size()`](/javascript-api/k6-experimental/browser/request/size), this returns the size of response headers and body sections. | +| response.url() | - | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/13-touchscreen.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/13-touchscreen.md new file mode 100644 index 0000000000..648b1fe8bb --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/13-touchscreen.md @@ -0,0 +1,13 @@ +--- +title: "Touchscreen" +excerpt: "Browser module: Touchscreen Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/touchscreen/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| touchscreen.tap(x, y) | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/14 Worker.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/14 Worker.md new file mode 100644 index 0000000000..f835aa09d3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/14 Worker.md @@ -0,0 +1,15 @@ +--- +title: "Worker" +excerpt: "Browser module: Worker Class" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/worker/ +--- + + + +## Supported APIs + +| Method | Playwright Relevant Distinctions | +| - | - | +| worker.url() | - | +| worker.evaluate(pageFunction[, arg]) | - | - | +| worker.evaluateHandle(pageFunction[, arg]) | - | - | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/context.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/context.md new file mode 100644 index 0000000000..4560e97b30 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/context.md @@ -0,0 +1,51 @@ +--- +title: 'context()' +excerpt: 'Browser module: context method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/context/ +--- + +Returns the current [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/). + +
+ +A 1-to-1 mapping between [Browser](/javascript-api/k6-experimental/browser) and `BrowserContext` means you cannot run `BrowserContexts` concurrently. If you wish to create a new `BrowserContext` while one already exists, you will need to [close](/javascript-api/k6-experimental/browser/browsercontext/close) the current one, and create a new one with either [newContext](/javascript-api/k6-experimental/browser/newcontext/) or [newPage](/javascript-api/k6-experimental/browser/newpage). All resources associated to the closed `BrowserContext` will also be closed and cleaned up (such as [Page](/javascript-api/k6-experimental/browser/page/)s). + +
+ +### Returns + +| Type | Description | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| object \| null | The current [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) if one has been created, otherwise `null`. | + + +### Example + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + console.log(browser.context()); // null + + const page1 = browser.newPage(); // implicitly creates a new browserContext + const context = browser.context(); // underlying live browserContext associated with browser + const page2 = context.newPage(); // shares the browserContext with page1 + + page1.close(); + page2.close(); + context.close(); +} +``` diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/isconnected.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/isconnected.md new file mode 100644 index 0000000000..84a6d20962 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/isconnected.md @@ -0,0 +1,49 @@ +--- +title: 'isConnected()' +excerpt: 'Browser module: isConnected method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/isconnected/ +--- + +
+ +This feature has **known issues**. +For details, refer to [#453](https://github.com/grafana/xk6-browser/issues/453). + +
+ +Indicates whether the [CDP](https://chromedevtools.github.io/devtools-protocol/) connection to the browser process is active or not. + +### Returns + +| Type | Description | +| ------- | ---------------------------------------------------------------------------------------------- | +| boolean | Returns `true` if the [browser module](/javascript-api/k6-experimental/browser) is connected to the browser application. Otherwise, returns `false`. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const isConnected = browser.isConnected(); + console.log(isConnected); // true +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/newcontext--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/newcontext--options--.md new file mode 100644 index 0000000000..dd70dc2c12 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/newcontext--options--.md @@ -0,0 +1,95 @@ +--- +title: 'newContext([options])' +excerpt: 'Browser module: newContext method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/newcontext/ +--- + +Creates and returns a new [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/), if one hasn't already been initialized for the [Browser](/javascript-api/k6-experimental/browser). If one has already been initialized an error is thrown. + +
+ +A 1-to-1 mapping between [Browser](/javascript-api/k6-experimental/browser) and `BrowserContext` means you cannot run `BrowserContexts` concurrently. Due to this restriction, if one already exists, it must be [close](/javascript-api/k6-experimental/browser/browsercontext/close)d first before creating a new one. + +
+ + + +| Parameter | Type | Default | Description | +|---------------------------------------------|---------|----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.bypassCSP | boolean | `false` | Whether to bypass a page's Content-Security-Policy. | +| options.colorScheme | string | `'light'` | Whether to display a page in dark or light mode by emulating the 'prefers-colors-scheme' media feature. It can be one of `'light'`, `'dark'`, `'no-preference'`. | +| options.deviceScaleFactor | number | `1` | Sets the resolution ratio in physical pixels to the resolution in CSS pixels i.e. if set higher than `1`, then images will look sharper on high pixel density screens. See an [example](#devicescalefactor-example) below. | +| options.extraHTTPHeaders | object | `null` | Contains additional HTTP headers to be sent with every request, where the keys are HTTP headers and values are HTTP header values. | +| options.geolocation | object | `null` | Sets the user's geographical location. | +| options.geolocation.latitude | number | `0` | Latitude should be between `-90` and `90`. | +| options.geolocation.longitude | number | `0` | Longitude should be between `-180` and `180`. | +| options.geolocation.accuracy | number | `0` | Accuracy should only be a non-negative number. Defaults to `0`. | +| options.hasTouch | boolean | `false` | Whether to simulate a device with touch events. | +| options.httpCredentials | object | `null` | Sets the credentials for HTTP authentication using Basic Auth. | +| options.httpCredentials.username | string | `''` | Username to pass to the web browser for Basic HTTP Authentication. | +| options.httpCredentials.password | string | `''` | Password to pass to the web browser for Basic HTTP Authentication. | +| options.ignoreHTTPSErrors | boolean | `false` | Whether to ignore HTTPS errors that may be caused by invalid certificates. | +| options.isMobile | boolean | `false` | Whether to simulate a mobile device. | +| options.javaScriptEnabled | boolean | `true` | Whether to activate JavaScript support for the context. | +| options.locale | string | system | Specifies the user's locale, such as `'en-US'`, `'tr-TR'`, etc. | +| options.offline | boolean | `false` | Whether to emulate an offline network. | +| options.permissions | Array | `null` | Permissions to grant for the context's pages. See [browserContext.grantPermissions()](/javascript-api/k6-experimental/browser/browsercontext/#browsercontext-grantpermissions-permissions-options) for the options. | +| options.reducedMotion | string | `'no-preference'` | Minimizes the amount of motion by emulating the 'prefers-reduced-motion' media feature. It can be one of `'reduce'` and `'no-preference'`. See [page.emulateMedia()](/javascript-api/k6-experimental/browser/page/emulatemedia) for the options. | +| options.screen | object | `{'width': 1280, 'height': 720}` | Sets a window screen size for all pages in the context. It can only be used when the viewport is set. | +| options.screen.width | number | `1280` | Page width in pixels. | +| options.screen.height | number | `720` | Page height in pixels. | +| options.timezoneID | string | system | Changes the context's timezone. See [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) for a list of supported timezone IDs. | +| options.userAgent | string | browser | Specifies the user agent to use in the context. | +| options.viewport | object | `{'width': 1280, 'height': 720}` | Sets a viewport size for all pages in the context. `null` disables the default viewport. | +| options.viewport.width | number | `1280` | Page width in pixels. | +| options.viewport.height | number | `720` | Page height in pixels. | + + + +### Returns + +| Type | Description | +| ------ | -------------------------------------------------------------------- | +| object | [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) object | + + +### deviceScaleFactor example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const context = browser.newContext({ + viewport: { + width: 375, + height: 812, + }, + deviceScaleFactor: 3, + }); + const page = context.newPage(); + + try { + await page.goto('https://test.k6.io/'); + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/newpage--options--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/newpage--options--.md new file mode 100644 index 0000000000..4f85262396 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/newpage--options--.md @@ -0,0 +1,99 @@ +--- +title: 'newPage([options])' +excerpt: 'Browser module: newPage method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/newpage/ +--- + +Creates and returns a new [Page](/javascript-api/k6-experimental/browser/page/) in a new [BrowserContext](/javascript-api/k6-experimental/browser/browsercontext/) if a `BrowserContext` hasn't already been initialized for the [Browser](/javascript-api/k6-experimental/browser). If a `BrowserContext` has already been initialized an error is thrown. + +
+ +A 1-to-1 mapping between [Browser](/javascript-api/k6-experimental/browser) and `BrowserContext` means you cannot run `BrowserContexts` concurrently. Due to this restriction, if one already exists, it must be [retrieved](/javascript-api/k6-experimental/browser/context) and [close](/javascript-api/k6-experimental/browser/browsercontext/close)d first before creating a new one. + +
+ +
+ +Pages that have been opened ought to be closed using [`Page.close`](/javascript-api/k6-experimental/browser/page/close/). Pages left open could potentially distort the results of Web Vital metrics. + +
+ + + +| Parameter | Type | Default | Description | +|---------------------------------------------|---------|----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| options | object | `null` | | +| options.bypassCSP | boolean | `false` | Whether to bypass a page's Content-Security-Policy. | +| options.colorScheme | string | `'light'` | Whether to display a page in dark or light mode by emulating the 'prefers-colors-scheme' media feature. It can be one of `'light'`, `'dark'`, `'no-preference'`. | +| options.deviceScaleFactor | number | `1` | Sets the resolution ratio in physical pixels to the resolution in CSS pixels i.e. if set higher than `1`, then images will look sharper on high pixel density screens. See an [example](#devicescalefactor-example) below. | +| options.extraHTTPHeaders | object | `null` | Contains additional HTTP headers to be sent with every request, where the keys are HTTP headers and values are HTTP header values. | +| options.geolocation | object | `null` | Sets the user's geographical location. | +| options.geolocation.latitude | number | `0` | Latitude should be between `-90` and `90`. | +| options.geolocation.longitude | number | `0` | Longitude should be between `-180` and `180`. | +| options.geolocation.accuracy | number | `0` | Accuracy should only be a non-negative number. Defaults to `0`. | +| options.hasTouch | boolean | `false` | Whether to simulate a device with touch events. | +| options.httpCredentials | object | `null` | Sets the credentials for HTTP authentication using Basic Auth. | +| options.httpCredentials.username | string | `''` | Username to pass to the web browser for Basic HTTP Authentication. | +| options.httpCredentials.password | string | `''` | Password to pass to the web browser for Basic HTTP Authentication. | +| options.ignoreHTTPSErrors | boolean | `false` | Whether to ignore HTTPS errors that may be caused by invalid certificates. | +| options.isMobile | boolean | `false` | Whether to simulate a mobile device. | +| options.javaScriptEnabled | boolean | `true` | Whether to activate JavaScript support for the context. | +| options.locale | string | system | Specifies the user's locale, such as `'en-US'`, `'tr-TR'`, etc. | +| options.offline | boolean | `false` | Whether to emulate an offline network. | +| options.permissions | Array | `null` | Permissions to grant for the context's pages. See [browserContext.grantPermissions()](/javascript-api/k6-experimental/browser/browsercontext/#browsercontext-grantpermissions-permissions-options) for the options. | +| options.reducedMotion | string | `'no-preference'` | Minimizes the amount of motion by emulating the 'prefers-reduced-motion' media feature. It can be one of `'reduce'` and `'no-preference'`. See [page.emulateMedia()](/javascript-api/k6-experimental/browser/page/emulatemedia) for the options. | +| options.screen | object | `{'width': 1280, 'height': 720}` | Sets a window screen size for all pages in the context. It can only be used when the viewport is set. | +| options.screen.width | number | `1280` | Page width in pixels. | +| options.screen.height | number | `720` | Page height in pixels. | +| options.timezoneID | string | system | Changes the context's timezone. See [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) for a list of supported timezone IDs. | +| options.userAgent | string | browser | Specifies the user agent to use in the context. | +| options.viewport | object | `{'width': 1280, 'height': 720}` | Sets a viewport size for all pages in the context. `null` disables the default viewport. | +| options.viewport.width | number | `1280` | Page width in pixels. | +| options.viewport.height | number | `720` | Page height in pixels. | + + + +### Returns + +| Type | Description | +| ------ | ------------------------------------------------ | +| object | [Page](/javascript-api/k6-experimental/browser/page/) object | + +### deviceScaleFactor example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default async function () { + const page = browser.newPage({ + viewport: { + width: 375, + height: 812, + }, + deviceScaleFactor: 3, + }); + + try { + await page.goto('https://test.k6.io/'); + } finally { + page.close(); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/version.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/version.md new file mode 100644 index 0000000000..5a296ad801 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/01 browser/version.md @@ -0,0 +1,42 @@ +--- +title: 'version()' +excerpt: 'Browser module: version method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-browser/version/ +--- + +Returns the browser application's version. + +### Returns + +| Type | Description | +| ------ | ---------------------------------- | +| string | The browser application's version. | + + +### Example + + + +```javascript +import { browser } from 'k6/experimental/browser'; + +export const options = { + scenarios: { + browser: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, +} + +export default function () { + const version = browser.version(); + console.log(version); // 105.0.5195.52 +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc.md new file mode 100644 index 0000000000..b18a7f40b3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc.md @@ -0,0 +1,63 @@ +--- +title: "grpc" +excerpt: "Experimental GRPC module" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/ +--- + + + +The `k6/experimental/grpc` module is an extension of the [`k6/net/grpc`](/javascript-api/k6-net-grpc/). It provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2. + +The key-difference between the two modules is new `Stream` class, which provides client and server streaming support. Our long-term goal is to make this module part of k6 core, and long-term to replace the [`k6/net/grpc`](/javascript-api/k6-net-grpc/) module. + +| Class/Method | Description | +|--------------|-------------| +| [Client](/javascript-api/k6-experimental/grpc/client) | gRPC client used for making RPC calls to a gRPC Server. | +| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-experimental/grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. | +| [Client.connect(address [,params])](/javascript-api/k6-experimental/grpc/client/client-connect) | Connects to a given gRPC service. | +| [Client.invoke(url, request [,params])](/javascript-api/k6-experimental/grpc/client/client-invoke) | Makes a unary RPC for the given service/method and returns a [Response](/javascript-api/k6-experimental/grpc/response). | +| [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) | Close the connection to the gRPC service. | +| [Params](/javascript-api/k6-experimental/grpc/params) | RPC Request specific options. | +| [Response](/javascript-api/k6-experimental/grpc/response) | Returned by RPC requests. | +| [Constants](/javascript-api/k6-experimental/grpc/constants) | Define constants to distinguish between [gRPC Response](/javascript-api/k6-experimental/grpc/response) statuses. | +| [Stream](/javascript-api/k6-experimental/grpc/stream) | Creates a new GRPC stream. | +| [Stream.on(event, handler)](/javascript-api/k6-experimental/grpc/stream/stream-on) | Adds a new listener to one of the possible stream event's. | +| [Stream.write(message)](/javascript-api/k6-experimental/grpc/stream/stream-write) | Writes a message to the stream. | +| [Stream.end()](/javascript-api/k6-experimental/grpc/stream/stream-end) | Signals to server that client finished sending. | + +## Metrics + +k6 takes specific measurements for gRPC requests. +For the complete list, refer to the [Metrics reference](/using-k6/metrics/reference#grpc). + +### Example + + + +```javascript +import grpc from 'k6/experimental/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/10-Client.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/10-Client.md new file mode 100644 index 0000000000..9d86ff0d97 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/10-Client.md @@ -0,0 +1,106 @@ +--- +title: Client +excerpt: 'Client is a gRPC client that can interact with a gRPC server.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/client/ +--- + +`Client` is a gRPC client that can interact with a gRPC server. + + + +| Method | Description | +|--------|-------------| +| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-experimental/grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. | +| [Client.loadProtoset(protosetPath)](/javascript-api/k6-experimental/grpc/client/client-loadprotoset) | Loads and parses the given protoset file to be made available for RPC requests. | +| [Client.connect(address [,params])](/javascript-api/k6-experimental/grpc/client/client-connect) | Opens a connection to the given gRPC server. | +| [Client.invoke(url, request [,params])](/javascript-api/k6-experimental/grpc/client/client-invoke) | Makes a unary RPC for the given service/method and returns a [Response](/javascript-api/k6-experimental/grpc/response). | +| [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) | Close the connection to the gRPC service. | + + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +// Download addsvc.proto for https://grpcbin.test.k6.io/, located at: +// https://raw.githubusercontent.com/moul/pb/master/addsvc/addsvc.proto +// and put it in the same folder as this script. +client.load(null, 'addsvc.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { timeout: '5s' }); + + const response = client.invoke('addsvc.Add/Sum', { + a: 1, + b: 2, + }); + console.log(response.message.v); // should print 3 + + client.close(); +}; +``` + +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'authorization.proto', 'route_guide.proto'); + +export function setup() { + client.connect('auth.googleapis.com:443'); + const resp = client.invoke('google.cloud.authorization.v1.AuthService/GetAccessToken', { + username: 'john.smith@k6.io', + password: 'its-a-secret', + }); + client.close(); + return resp.message.accessToken; +} + +export default (token) => { + client.connect('route.googleapis.com:443'); + const metadata = { + authorization: `bearer ${token}`, + }; + const response = client.invoke( + 'google.cloud.route.v1.RoutingService/GetFeature', + { + latitude: 410248224, + longitude: -747127767, + }, + { metadata } + ); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + client.close(); +}; +``` + +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'language_service.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('language.googleapis.com:443'); + } + const response = client.invoke('google.cloud.language.v1.LanguageService/AnalyzeSentiment', {}); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + // Do NOT close the client +}; +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md new file mode 100644 index 0000000000..563cecc13e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md @@ -0,0 +1,44 @@ +--- +title: "Client.load(importPaths, ...protoFiles)" +excerpt: 'Loads and parses the protocol buffer descriptors so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/client/client-load/ +--- + +Loads and parses the protocol buffer descriptors so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema. + +Must be called within the [`init` phase](/using-k6/test-lifecycle). + +| Parameter | Type | Description | +|-----------|------|-------------| +| importPaths | Array<string> \| `null` | The paths used to search for dependencies that are referenced in import statements in proto source files. If no import paths are provided then "." (current directory) is assumed to be the only import path. | +| protoFiles | Array<string> | [Rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) for the list of proto files to load/parse. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.load([], 'language_service.proto'); +``` + +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +client.load( + ['../googleapis/google'], + 'spanner/admin/instance/v1/spanner_instance_admin.proto', + 'spanner/admin/instance/v1/spanner_instance_admin.proto', + 'spanner/v1/spanner.proto' +); +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/11-Client-load-protoset.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/11-Client-load-protoset.md new file mode 100644 index 0000000000..1d73ac89b1 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/11-Client-load-protoset.md @@ -0,0 +1,26 @@ +--- +title: "Client.loadProtoset(protosetPath)" +excerpt: 'Loads and parses the protoset file (serialized FileDescriptor set) so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/client/client-loadprotoset/ +--- + +Loads and parses the protoset file (serialized FileDescriptor set) so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema. + +Must be called within the [`init` phase](/using-k6/test-lifecycle). + +| Parameter | Type | Description | +|-----------|------|-------------| +| protosetPath | string | The path of the protoset file. If no import paths are provided then "." (current directory) is assumed to be the only import path. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.loadProtoset('./dummy.protoset'); +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md new file mode 100644 index 0000000000..1ca42c349a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/20-Client-connect-connect-address-params.md @@ -0,0 +1,128 @@ +--- +title: "Client.connect(address [,params])" +excerpt: 'Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/client/client-connect/ +--- + +Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown. Cannot be called during the [`init` phase](/using-k6/test-lifecycle). + +See [Client.close()](/javascript-api/k6-experimental/grpc/client/client-close) to close the connection. + +| Parameter | Type | Description | +|-----------|------|-------------| +| address | string | The address of the gRPC server. Should be in the form: `host:port` with no protocol prefix e.g. `grpc.k6.io:443`. The host must be a literal IP address, or a host name that can be resolved to IP addresses. The port must be a literal port number or a service name e.g. `:443` or `:https`. If the host is a literal IPv6 address it must be enclosed in square brackets, as in `[2001:db8::1]:80` or `[fe80::1%zone]:80`. | +| params (optional) | object | [ConnectParams](#connectparams) object containing additional connect parameters. | + + +## ConnectParams + +| Name | Type | Description | +|------|------|-------------| +| `ConnectParams.plaintext` | bool | If `true` will connect to the gRPC server using plaintext i.e. insecure. Defaults to `false` i.e. secure via TLS. | +| `ConnectParams.reflect` | boolean | Whether to use the [gRPC server reflection protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) when connecting. | +| `ConnectParams.reflectMetadata` | object | Object with key-value pairs representing custom metadata the user would like to add to the reflection request. | +| `ConnectParams.timeout` | string / number | Connection timeout to use. Default timeout is `"60s"`.
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | +| `ConnectParams.maxReceiveSize` | number | Sets the maximum message size in bytes the client can receive. Defaults to 0. | +| `ConnectParams.maxSendSize` | number | Sets the maximum message size in bytes the client can send. Defaults to 0. | +| `ConnectParams.tls` (optional) | object | [TLS](#tls) settings of the connection. Defaults to `null`. | + +## TLS + +TLS settings of the connection. If not defined, the main TLS config from options will be used. + +| Name | Type | Description | +|------|------|-------------| +| `tls.cert` | string | PEM formatted client certificate. | +| `tls.key` | string | PEM formatted client private key. | +| `tls.password` | string | Password for decrypting the client's private key. | +| `tls.cacerts` | string / array | PEM formatted strings of the certificate authorities. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +export default () => { + client.connect('localhost:8080'); +}; +``` +
+ +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); + +export default () => { + client.connect('localhost:8080', { plaintext: true }); +}; +``` +
+ +
+ +```javascript +import grpc from "k6/experimental/grpc"; +import { check } from "k6"; +import { SharedArray } from "k6/data"; +import exec from "k6/execution"; + +// note: the services in this example don't exist. If you would like +// to run this example, make sure to replace the URLs, and +// the cacerts, cert, key, and password variables. +const grpcArgs = new SharedArray("grpc", () => { + // Using SharedArray here so that not every VU gets a copy of every certificate a key + return [ + { + host: "foo1.grpcbin.test.k6.io:9001", + plaintext: false, + params: { + tls: { + cacerts: [open("cacerts0.pem")], + cert: open("cert0.pem"), + key: open("key0.pem"), + }, + }, + }, + { + host: "foo2.grpcbin.test.k6.io:9002", + params: { + plaintext: false, + tls: { + cacerts: open("cacerts1.pem"), + cert: open("cert1.pem"), + key: open("key1.pem"), + password: "cert1-passphrase", + }, + }, + }, + ]; +}); + +const client = new grpc.Client(); + +export default () => { + if (__ITER === 0) { + // Take one config and use it for this one VU + const grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; + client.connect(grpcArg.host, grpcArg.params); + } + + const response = client.invoke("hello.HelloService/SayHello", { + greeting: "Bert", + }); + + check(response, { + "status is OK": (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); +}; +``` +
\ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/30-Client-invokerpc-url-request-params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/30-Client-invokerpc-url-request-params.md new file mode 100644 index 0000000000..c0b2499f9d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/30-Client-invokerpc-url-request-params.md @@ -0,0 +1,52 @@ +--- +title: "Client.invoke(url, request [,params])" +excerpt: 'Invokes an unary RPC request to the given method.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/client/client-invoke/ +--- + +Invokes an unary RPC request to the given method. + +The given method to invoke must have its RPC schema previously loaded via the [Client.load()](/javascript-api/k6-experimental/grpc/client/client-load) function, otherwise an +error will be thrown. + +[Client.connect()](/javascript-api/k6-experimental/grpc/client/client-connect) must be called first before invoking a request, otherwise an error will be thrown. + +| Parameter | Type | Description | +|-----------|------|-------------| +| url | string | The gRPC method url to invoke, in the form `/package.Service/Method`, e.g. `/google.cloud.language.v1.LanguageService/AnalyzeSentiment`. The leading slash `/` is optional. | +| request | object | The canonical request object, as-per the [Protobuf JSON Mapping](https://developers.google.com/protocol-buffers/docs/proto3#json). | +| params (optional) | object | [Params](/javascript-api/k6-experimental/grpc/params) object containing additional request parameters. + +### Returns + +| Type | Description | +|------|-------------| +| `Response` | gRPC [Response](/javascript-api/k6-experimental/grpc/response) object. | + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'routeguide.proto'); + +export default () => { + client.connect('localhost:10000', { plaintext: true }); + const response = client.invoke('main.RouteGuide/GetFeature', { + latitude: 410248224, + longitude: -747127767, + }); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + console.log(response.message.name); + // output: 3 Hasta Way, Newton, NJ 07860, USA + + client.close(); +}; +``` + +
+ diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/40-Client-close.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/40-Client-close.md new file mode 100644 index 0000000000..fc25beb99a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20 Client/40-Client-close.md @@ -0,0 +1,24 @@ +--- +title: "Client.close()" +excerpt: 'Close the connection to the gRPC service. Tear down all underlying connections.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/client/client-close/ +--- + +Close the connection to the gRPC service. Tear down all underlying connections. + +### Examples + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('localhost:8080'); + client.close(); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20-Params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20-Params.md new file mode 100644 index 0000000000..635705d6d2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/20-Params.md @@ -0,0 +1,43 @@ +--- +title: "Params" +head_title: 'gRPC.params' +excerpt: 'Params is an object used by the gRPC methods that generate RPC requests.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/params/ +--- + +*Params* is an object used by the gRPC methods that generate RPC requests. *Params* contains request-specific options like headers that should be inserted into the request. + +| Name | Type | Description | +|------|------|-------------| +| `Params.metadata` | object | Object with key-value pairs representing custom metadata the user would like to add to the request. Values of [keys ending with `-bin`](https://grpc.io/docs/what-is-grpc/core-concepts/#metadata) will be treated as binary data. | +| `Params.tags` | object | Key-value pairs where the keys are names of tags and the values are tag values. Response time metrics generated as a result of the request will have these tags added to them, allowing the user to filter out those results specifically, when looking at results data. | +| `Params.timeout` | string / number | Request timeout to use. Default timeout is 60 seconds (`"60s"`).
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | + + +### Example of custom metadata headers and tags + +
+ +```javascript +import grpc from 'k6/experimental/grpc'; + +const client = new grpc.Client(); +client.load([], 'route_guide.proto'); + +export default function () { + const req = { + latitude: 410248224, + longitude: -747127767, + }; + const params = { + metadata: { + 'x-my-header': 'k6test', + 'x-my-header-bin': new Uint8Array([1, 2, 3]), + }, + tags: { k6test: 'yes' }, + }; + const response = client.invoke('main.RouteGuide/GetFeature', req, params); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/10-Stream-on.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/10-Stream-on.md new file mode 100644 index 0000000000..2a7b104740 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/10-Stream-on.md @@ -0,0 +1,67 @@ +--- +title: "Stream.on()" +excerpt: 'Set up handler functions for various events on the GRPC stream.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/stream/stream-on/ +--- + +Set up handler functions for various events on the GRPC stream. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------- | +| event | string | The event name to define a handler for. | +| handler | function | The function to call when the event happens. | + +Possible events: + +| Event name | Description | +| --------- | -------- | +| data | Emitted when the server sends data. | +| error | Emitted when an error occurs. In case of the error, an [`Error`](/javascript-api/k6-experimental/grpc/stream/error/) object sends to the handler function.| +| end | Emitted when the server closes the incoming stream. | + + +### Example + +
+ +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const client = new Client(); +client.load([], '../../grpc_server/route_guide.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('127.0.0.1:10000', { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + // sets up a handler for the data (server sends data) event + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + console.log('Passed', stats.featureCount, 'features'); + console.log('Traveled', stats.distance, 'meters'); + console.log('It took', stats.elapsedTime, 'seconds'); + }); + + // sets up a handler for the end event (stream closes) + stream.on('end', function () { + // The server has finished sending + client.close(); + console.log('All done'); + }); + + // sets up a handler for the error event (an error occurs) + stream.on('error', function (e) { + // An error has occurred and the stream has been closed. + console.log('Error: ' + JSON.stringify(e)); + }); + + sleep(1); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/15-Stream-error.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/15-Stream-error.md new file mode 100644 index 0000000000..527170f627 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/15-Stream-error.md @@ -0,0 +1,14 @@ +--- +title: "Error" +head_title: 'gRPC.Error' +excerpt: 'The error object of a gRPC stream.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/stream/stream-error/ +--- + +The error object is the object that is passed to the `error` event handler function. + +| Name | Type | Description | +|------|------|-------------| +| `Error.code` | number | A gRPC error code. | +| `Error.details` | array | A list details attached to the error. | +| `Error.message` | string | An original error message. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-end.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-end.md new file mode 100644 index 0000000000..d3c9560e85 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-end.md @@ -0,0 +1,46 @@ +--- +title: "Stream.end()" +excerpt: 'Signals to the server that the client has finished sending.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/stream/stream-end/ +--- + +Signals to the server that the client has finished sending messages. + +### Example + +
+ +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const client = new Client(); +client.load([], '../../grpc_server/route_guide.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('127.0.0.1:10000', { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + console.log('Passed', stats.featureCount, 'features'); + console.log('Traveled', stats.distance, 'meters'); + console.log('It took', stats.elapsedTime, 'seconds'); + }); + + // send 2 items + stream.write({ latitude: 406109563, longitude: -742186778 }); + stream.write({ latitude: 416802456, longitude: -742370183 }); + + // send end-signal to the server + stream.end(); + + sleep(1); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-write.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-write.md new file mode 100644 index 0000000000..b289b92b87 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30 Stream/40-Stream-write.md @@ -0,0 +1,42 @@ +--- +title: "Stream.write()" +excerpt: 'Writes a message to the stream.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/stream/stream-write/ +--- + +Writes a message to the stream. + +### Example + +
+ +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const client = new Client(); +client.load([], '../../grpc_server/route_guide.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('127.0.0.1:10000', { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + }); + + // send an item + stream.write({ latitude: 406109563, longitude: -742186778 }); + + // send end-signal to the server + stream.end(); + + sleep(1); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30-Response.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30-Response.md new file mode 100644 index 0000000000..3738e2a53e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/30-Response.md @@ -0,0 +1,44 @@ +--- +title: "Response" +head_title: 'gRPC.Response' +excerpt: 'The response object of a gRPC request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/response/ +--- + +| Name | Type | Description | +|------|------|-------------| +| `Response.status` | number | The response gRPC status code. Use the gRPC [status constants](/javascript-api/k6-experimental/grpc/constants) to check equality. | +| `Response.message` | object | The successful protobuf message, serialized to JSON. Will be `null` if `status !== grpc.StatusOK`. | +| `Response.headers` | object | Key-value pairs representing all the metadata headers returned by the gRPC server. | +| `Response.trailers` | object | Key-value pairs representing all the metadata trailers returned by the gRPC server. | +| `Response.error` | object | If `status !== grpc.StatusOK` then the error protobuf message, serialized to JSON; otherwise `null`. | + +### Example + + + +```javascript +import grpc from 'k6/experimental/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/40-Constants.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/40-Constants.md new file mode 100644 index 0000000000..8045bbda83 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/40-Constants.md @@ -0,0 +1,57 @@ +--- +title: 'Constants' +excerpt: 'Define constants to distinguish between gRPC Response' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/constants/ +--- + +Define constants to distinguish between [gRPC Response](/javascript-api/k6-experimental/grpc/response) statuses. + +| Constant | Description | +|----------|-------------| +| `StatusOK` | OK is returned on success. | +| `StatusCanceled` | Canceled indicates the operation was canceled (typically by the caller). | +| `StatusUnknown` | Unknown error. | +| `StatusInvalidArgument` | InvalidArgument indicates the client specified an invalid argument. | +| `StatusDeadlineExceeded` | DeadlineExceeded means operation expired before completion. | +| `StatusNotFound` | NotFound means some requested entity (e.g., file or directory) was not found. | +| `StatusAlreadyExists` | AlreadyExists means an attempt to create an entity failed because one already exists. | +| `StatusPermissionDenied` | PermissionDenied indicates the caller does not have permission to execute the specified operation. | +| `StatusResourceExhausted` | ResourceExhausted indicates some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. | +| `StatusFailedPrecondition` | FailedPrecondition indicates operation was rejected because the system is not in a state required for the operation's execution. | +| `StatusAborted` | Aborted indicates the operation was aborted, typically due to a concurrency issue like sequencer check failures, transaction aborts, etc. | +| `StatusOutOfRange` | OutOfRange means operation was attempted past the valid range. E.g., seeking or reading past end of file. | +| `StatusUnimplemented` | Unimplemented indicates operation is not implemented or not supported/enabled in this service. | +| `StatusInternal` | Internal errors. Means some invariants expected by the underlying system have been broken. | +| `StatusUnavailable` | Unavailable indicates the service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. | +| `StatusDataLoss` | DataLoss indicates unrecoverable data loss or corruption. | +| `StatusUnauthenticated` | Unauthenticated indicates the request does not have valid authentication credentials for the operation. | + +### Example + + + +```javascript +import grpc from 'k6/experimental/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/50-Stream.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/50-Stream.md new file mode 100644 index 0000000000..0f62756252 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 grpc/50-Stream.md @@ -0,0 +1,200 @@ +--- +title: Stream +excerpt: 'GRPC Streams' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/grpc/stream/ +--- + +Using a GRPC client creates a stream. An important note that the client should be already connected (client.connect called) to the server before creating a stream. + +| Method | Description | +|--------|-------------| +| [Stream(client, url, [,params])](/javascript-api/k6-experimental/grpc/stream) | Using a GRPC client creates a stream. | +| [Stream.write(message)](/javascript-api/k6-experimental/grpc/stream/stream-write) | Writes a message to the stream. | +| [Stream.on(event, handler)](/javascript-api/k6-experimental/grpc/stream/stream-on) | Set up handler functions for various events on the GRPC stream. | +| [Stream.end()](/javascript-api/k6-experimental/grpc/stream/stream-end) | Signals to the server that the client has finished sending. | + +### Examples + +_A k6 script that sends several randomly chosen points from the pre-generated feature database with a variable delay in between. Prints the statistics when they are sent from the server._ + + + +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000'; +const GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto'; + +const client = new Client(); +client.load([], GRPC_PROTO_PATH); + +// a sample DB of points +const DB = [ + { + location: { latitude: 407838351, longitude: -746143763 }, + name: 'Patriots Path, Mendham, NJ 07945, USA', + }, + { + location: { latitude: 408122808, longitude: -743999179 }, + name: '101 New Jersey 10, Whippany, NJ 07981, USA', + }, + { + location: { latitude: 413628156, longitude: -749015468 }, + name: 'U.S. 6, Shohola, PA 18458, USA', + }, + { + location: { latitude: 419999544, longitude: -740371136 }, + name: '5 Conners Road, Kingston, NY 12401, USA', + }, + { + location: { latitude: 414008389, longitude: -743951297 }, + name: 'Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA', + }, + { + location: { latitude: 419611318, longitude: -746524769 }, + name: '287 Flugertown Road, Livingston Manor, NY 12758, USA', + }, + { + location: { latitude: 406109563, longitude: -742186778 }, + name: '4001 Tremley Point Road, Linden, NJ 07036, USA', + }, + { + location: { latitude: 416802456, longitude: -742370183 }, + name: '352 South Mountain Road, Wallkill, NY 12589, USA', + }, + { + location: { latitude: 412950425, longitude: -741077389 }, + name: 'Bailey Turn Road, Harriman, NY 10926, USA', + }, + { + location: { latitude: 412144655, longitude: -743949739 }, + name: '193-199 Wawayanda Road, Hewitt, NJ 07421, USA', + }, +]; + +export default () => { + if (__ITER == 0) { + client.connect(GRPC_ADDR, { plaintext: true }); + } + + const stream = new Stream(client, 'main.RouteGuide/RecordRoute'); + + stream.on('data', (stats) => { + console.log('Finished trip with', stats.pointCount, 'points'); + console.log('Passed', stats.featureCount, 'features'); + console.log('Travelled', stats.distance, 'meters'); + console.log('It took', stats.elapsedTime, 'seconds'); + }); + + stream.on('error', (err) => { + console.log('Stream Error: ' + JSON.stringify(err)); + }); + + stream.on('end', () => { + client.close(); + console.log('All done'); + }) + + // send 5 random items + for (let i = 0; i < 5; i++) { + const point = DB[Math.floor(Math.random() * DB.length)]; + pointSender(stream, point); + } + + // close the client stream + stream.end(); + + sleep(1); +}; + +const pointSender = (stream, point) => { + console.log( + 'Visiting point ' + + point.name + + ' ' + + point.location.latitude / COORD_FACTOR + + ', ' + + point.location.longitude / COORD_FACTOR + ); + + // send the location to the server + stream.write(point.location); + + sleep(0.5); +}; +``` + + + +_A k6 script that sends a rectangle message and results (features) are streamed back to the client._ + + + +```javascript +import { Client, Stream } from 'k6/experimental/grpc'; +import { sleep } from 'k6'; + +const COORD_FACTOR = 1e7; + +const GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000'; +const GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto'; + +const client = new Client(); + +client.load([], GRPC_PROTO_PATH); + +export default () => { + client.connect(GRPC_ADDR, { plaintext: true }); + + const stream = new Stream(client, 'main.FeatureExplorer/ListFeatures', null); + + stream.on('data', function (feature) { + console.log( + 'Found feature called "' + + feature.name + + '" at ' + + feature.location.latitude / COORD_FACTOR + + ', ' + + feature.location.longitude / COORD_FACTOR + ); + }); + + stream.on('end', function () { + // The server has finished sending + client.close(); + console.log('All done'); + }); + + stream.on('error', function (e) { + // An error has occurred and the stream has been closed. + console.log('Error: ' + JSON.stringify(e)); + }); + + // send a message to the server + stream.write({ + lo: { + latitude: 400000000, + longitude: -750000000, + }, + hi: { + latitude: 420000000, + longitude: -730000000, + }, + }); + + sleep(0.5); +}; +``` + + +The preceding examples use a demo server, which you can run with the following command (Golang should be installed) in [k6 repository's root](https://github.com/grafana/k6): + + + +```bash +$ go run -mod=mod examples/grpc_server/*.go +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis.md new file mode 100644 index 0000000000..a9473fa561 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis.md @@ -0,0 +1,32 @@ +--- +title: "redis" +excerpt: "k6 Redis experimental API" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/ +--- + + + + +The [Redis](https://redis.io/) module provides a client library that makes it possible to interact with Redis directly from a k6 script. +With this module, you can: +- Load test Redis +- Use Redis as a data store for test-script logic. + +Though the API intends to be thorough and extensive, it does not expose the whole Redis API. +Instead, the intent is to expose Redis for use cases most appropriate to k6. + +| Class | Description | +| :------------------------------------------ | :--------------------------------------------------------------------------------------------- | +| [Client](/javascript-api/k6-experimental/redis/client) | Client that exposes allowed interactions with Redis. | +| [Options](/javascript-api/k6-experimental/redis/options) | Options used to configure the behavior of the [Redis Client](/javascript-api/k6-experimental/redis/client). | + +### Notes on usage + +The `Client` exposes a [promise](https://javascript.info/promise-basics)-based API. +Unlike most other current k6 modules and extensions, +which operate in a synchronous manner, +the Redis `Client` operates in an asynchronous manner. +In practice, this means that using the Redis `Client`'s methods won't block test execution, +and that the test will continue to run even if the Redis `Client` isn't ready to respond to the request. +The `async` and `await` keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains +(for details, refer to the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)). \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client.md new file mode 100644 index 0000000000..ad156dd5f4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client.md @@ -0,0 +1,176 @@ +--- +title: 'Client' +excerpt: 'Client is a Redis client to interact with a Redis server or cluster.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/ +--- + +`Client` is a Redis client to interact with a Redis server or cluster. It exposes a promise-based API, which users can interact with in an asynchronous manner. + +Though the API intends to be thorough and extensive, it does not expose the whole Redis API. +Instead, the intent is to expose Redis for use cases most appropriate to k6. + +Note that the `Client` is configured through the [`Options`](/javascript-api/k6-experimental/redis/options) object. + +## Example + + + + +```javascript +import { check } from 'k6'; +import http from 'k6/http'; +import redis from 'k6/experimental/redis'; +import exec from 'k6/execution'; +import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js'; + +export const options = { + scenarios: { + redisPerformance: { + executor: 'shared-iterations', + vus: 10, + iterations: 200, + exec: 'measureRedisPerformance', + }, + usingRedisData: { + executor: 'shared-iterations', + vus: 10, + iterations: 200, + exec: 'measureUsingRedisData', + }, + }, +}; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +// Prepare an array of crocodile ids for later use +// in the context of the measureUsingRedisData function. +const crocodileIDs = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + +export async function measureRedisPerformance() { + // VUs are executed in a parallel fashion, + // thus, to ensure that parallel VUs are not + // modifying the same key at the same time, + // we use keys indexed by the VU id. + const key = `foo-${exec.vu.idInTest}`; + + await redisClient.set(key, 1); + await redisClient.incrBy(key, 10); + const value = await redisClient.get(key); + if (value !== '11') { + throw new Error('foo should have been incremented to 11'); + } + + await redisClient.del(key); + if (await redisClient.exists(key) !== 0) { + throw new Error('foo should have been deleted'); + } +} + +export async function setup() { + await redisClient.sadd('crocodile_ids', ...crocodileIDs); +} + +export async function measureUsingRedisData() { + // Pick a random crocodile id from the dedicated redis set, + // we have filled in setup(). + const randomID = await redisClient.srandmember('crocodile_ids'); + const url = `https://test-api.k6.io/public/crocodiles/${randomID}`; + const res = await http.asyncRequest("GET", url); + + check(res, {'status is 200': (r) => r.status === 200}); + + await redisClient.hincrby('k6_crocodile_fetched', url, 1); +} + +export async function teardown() { + await redisClient.del('crocodile_ids'); +} + +export function handleSummary(data) { + redisClient + .hgetall('k6_crocodile_fetched') + .then((fetched) => Object.assign(data, { k6_crocodile_fetched: fetched })) + .then((data) => redisClient.set(`k6_report_${Date.now()}`, JSON.stringify(data))) + .then(() => redisClient.del('k6_crocodile_fetched')); + + return { + stdout: textSummary(data, { indent: ' ', enableColors: true }), + }; +} +``` + + + +## key/value methods + +| Method | Redis command | Description | +| :------------------------------------------------------------------------------- | :----------------------------------------------------- | :-------------------------------------------------------------------------- | +| [`Client.set(key, value, expiration)`](/javascript-api/k6-experimental/redis/client/client-set) | **[SET](https://redis.io/commands/set)** | Set `key` to hold `value`, with a time to live equal to `expiration`. | +| [`Client.get(key)`](/javascript-api/k6-experimental/redis/client/client-get) | **[GET](https://redis.io/commands/get)** | Get the value of `key`. | +| [`Client.getSet(key, value)`](/javascript-api/k6-experimental/redis/client/client-getset) | **[GETSET](https://redis.io/commands/getset)** | Atomically sets `key` to `value` and returns the old value stored at `key`. | +| [`Client.del(keys)`](/javascript-api/k6-experimental/redis/client/client-del) | **[DEL](https://redis.io/commands/del)** | Removes the specified keys. | +| [`Client.getDel(key)`](/javascript-api/k6-experimental/redis/client/client-getdel) | **[GETDEL](https://redis.io/commands/getdel)** | Get the value of `key` and delete the key. | +| [`Client.exists(keys)`](/javascript-api/k6-experimental/redis/client/client-exists) | **[EXISTS](https://redis.io/commands/exists)** | Returns the number of `key` arguments that exist. | +| [`Client.incr(key)`](/javascript-api/k6-experimental/redis/client/client-incr) | **[INCR](https://redis.io/commands/incr)** | Increments the number stored at `key` by one. | +| [`Client.incrBy(key, increment)`](/javascript-api/k6-experimental/redis/client/client-incrby) | **[INCRBY](https://redis.io/commands/incrby)** | Increments the number stored at `key` by `increment`. | +| [`Client.decr(key)`](/javascript-api/k6-experimental/redis/client/client-decr) | **[DECR](https://redis.io/commands/decr)** | Decrements the number stored at `key` by one. | +| [`Client.decrBy(key, decrement)`](/javascript-api/k6-experimental/redis/client/client-decrby) | **[DECRBY](https://redis.io/commands/decrby)** | Decrements the number stored at `key` by `decrement`. | +| [`Client.randomKey()`](/javascript-api/k6-experimental/redis/client/client-randomkey) | **[RANDOMKEY](https://redis.io/commands/randomkey)** | Returns a random key's value. | +| [`Client.mget(keys)`](/javascript-api/k6-experimental/redis/client/client-mget) | **[MGET](https://redis.io/commands/mget)** | Returns the values of all specified keys. | +| [`Client.expire(key, seconds)`](/javascript-api/k6-experimental/redis/client/client-expire) | **[EXPIRE](https://redis.io/commands/expire)** | Sets a timeout on key, after which the key will automatically be deleted. | +| [`Client.ttl(key)`](/javascript-api/k6-experimental/redis/client/client-ttl) | **[TTL](https://redis.io/commands/ttl)** | Returns the remaining time to live of a key that has a timeout. | +| [`Client.persist(key)`](/javascript-api/k6-experimental/redis/client/client-persist) | **[PERSIST](https://redis.io/commands/persist)** | Removes the existing timeout on key. | + +## List methods + +| Method | Redis command | Description | +| :------------------------------------------------------------------------------- | :----------------------------------------------- | :------------------------------------------------------------------------------ | +| [`Client.lpush(key, values)`](/javascript-api/k6-experimental/redis/client/client-lpush) | **[LPSUH](https://redis.io/commands/lpush)** | Inserts all the specified values at the head of the list stored at `key`. | +| [`Client.rpush(key, values)`](/javascript-api/k6-experimental/redis/client/client-rpush) | **[RPUSH](https://redis.io/commands/rpush)** | Inserts all the specified values at the tail of the list stored at `key`. | +| [`Client.lpop(key)`](/javascript-api/k6-experimental/redis/client/client-lpop) | **[LPOP](https://redis.io/commands/lpop)** | Removes and returns the first element of the list stored at `key`. | +| [`Client.rpop(key)`](/javascript-api/k6-experimental/redis/client/client-rpop) | **[RPOP](https://redis.io/commands/rpop)** | Removes and returns the last element of the list stored at `key`. | +| [`Client.lrange(key, start, stop)`](/javascript-api/k6-experimental/redis/client/client-lrange) | **[LRANGE](https://redis.io/commands/lrange)** | Returns the specified elements of the list stored at `key`. | +| [`Client.lindex(key, start, stop)`](/javascript-api/k6-experimental/redis/client/client-lindex) | **[LINDEX](https://redis.io/commands/lindex)** | Returns the specified element of the list stored at `key`. | +| [`Client.lset(key, index, element)`](/javascript-api/k6-experimental/redis/client/client-lset) | **[LSET](https://redis.io/commands/lset)** | Sets the list element at `index` to `element`. | +| [`Client.lrem(key, count, value)`](/javascript-api/k6-experimental/redis/client/client-lrem) | **[LREM](https://redis.io/commands/lrem)** | Removes the first `count` occurrences of `value` from the list stored at `key`. | +| [`Client.llen(key)`](/javascript-api/k6-experimental/redis/client/client-llen) | **[LLEN](https://redis.io/commands/llen)** | Returns the length of the list stored at `key`. | + + +## Hash methods + +| Method | Redis command | Description | +| :-------------------------------------------------------------------------------------- | :------------------------------------------------- | :--------------------------------------------------------------------------------------------------- | +| [`Client.hset(key, field, value)`](/javascript-api/k6-experimental/redis/client/client-hset) | **[HSET](https://redis.io/commands/hset)** | Sets the specified field in the hash stored at `key` to `value`. | +| [`Client.hsetnx(key, field, value)`](/javascript-api/k6-experimental/redis/client/client-hsetnx) | **[HSETNX](https://redis.io/commands/hsetnx)** | Sets the specified field in the hash stored at `key` to `value`, only if `field` does not yet exist. | +| [`Client.hget(key, field)`](/javascript-api/k6-experimental/redis/client/client-hget) | **[HGET](https://redis.io/commands/hget)** | Returns the value associated with `field` in the hash stored at `key`. | +| [`Client.hdel(key, fields)`](/javascript-api/k6-experimental/redis/client/client-hdel) | **[HDEL](https://redis.io/commands/hdel)** | Deletes the specified fields from the hash stored at `key`. | +| [`Client.hgetall(key)`](/javascript-api/k6-experimental/redis/client/client-hgetall) | **[HGETALL](https://redis.io/commands/hgetall)** | Returns all fields and values of the hash stored at `key`. | +| [`Client.hkeys(key)`](/javascript-api/k6-experimental/redis/client/client-hkeys) | **[HKEYS](https://redis.io/commands/hkeys)** | Returns all fields of the hash stored at `key`. | +| [`Client.hvals(key)`](/javascript-api/k6-experimental/redis/client/client-hvals) | **[HVALS](https://redis.io/commands/hvals)** | Returns all values of the hash stored at `key`. | +| [`Client.hlen(key)`](/javascript-api/k6-experimental/redis/client/client-hlen) | **[HLEN](https://redis.io/commands/hlen)** | Returns the number of fields in the hash stored at `key`. | +| [`Client.hincrby(key, field, increment)`](/javascript-api/k6-experimental/redis/client/client-hincrby) | **[HINCRBY](https://redis.io/commands/hincrby)** | Increments the integer value of `field` in the hash stored at `key` by `increment`. | + +## Set methods + +| Method | Redis command | Description | +| :-------------------------------------------------------------------------------- | :--------------------------------------------------------- | :----------------------------------------------------------------------- | +| [`Client.sadd(key, members)`](/javascript-api/k6-experimental/redis/client/client-sadd) | **[SADD](https://redis.io/commands/sadd)** | Adds the specified members to the set stored at `key`. | +| [`Client.srem(key, members)`](/javascript-api/k6-experimental/redis/client/client-srem) | **[SREM](https://redis.io/commands/srem)** | Removes the specified members from the set stored at `key`. | +| [`Client.sismember(key, member)`](/javascript-api/k6-experimental/redis/client/client-sismember) | **[SISMEMBER](https://redis.io/commands/sismember)** | Returns if member is a member of the set stored at `key`. | +| [`Client.smembers(key)`](/javascript-api/k6-experimental/redis/client/client-smembers) | **[SMEMBERS](https://redis.io/commands/smembers)** | Returns all the members of the set values stored at `keys`. | +| [`Client.srandmember(key)`](/javascript-api/k6-experimental/redis/client/client-srandmember) | **[SRANDMEMBER](https://redis.io/commands/srandmember)** | Returns a random element from the set value stored at `key`. | +| [`Client.spop(key)`](/javascript-api/k6-experimental/redis/client/client-spop) | **[SPOP](https://redis.io/commands/spop)** | Removes and returns a random element from the set value stored at `key`. | + +## miscellaneous + +| Method | Description | +| :-------------------------------------------------------------------------------------- | :---------------------------------- | +| [`Client.sendCommand(command, args)`](/javascript-api/k6-experimental/redis/client/client-sendcommand) | Send a command to the Redis server. | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-decr.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-decr.md new file mode 100644 index 0000000000..965a3be502 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-decr.md @@ -0,0 +1,54 @@ +--- +title: 'Client.decr(key)' +excerpt: 'Decrements the number stored at `key` by one.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-decr/ +--- + +Decrements the number stored at `key` by one. If the key does not exist, it is set to zero before performing the operation. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :-------------------- | +| `key` | string | the key to decrement. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of `key` after the decrement. | If the key contains a value of the wrong type, or contains a string that cannot be represented as an integer, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 10, 0); + + let value; + value = await redisClient.incr('mykey'); + value = await redisClient.incrBy('mykey', value); + value = await redisClient.decrBy('mykey', value); + value = await redisClient.decr('mykey'); + + if (value !== -1) { + throw new Error('mykey should have been -1'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-decrby.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-decrby.md new file mode 100644 index 0000000000..a5d2a8a930 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-decrby.md @@ -0,0 +1,50 @@ +--- +title: 'Client.decrBy(key, decrement)' +excerpt: 'Decrements the number stored at `key` by `decrement`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-decrby/ +--- + +Decrements the number stored at `key` by `decrement`. If the key does not exist, it is set to zero before performing the operation. + +### Parameters + +| Parameter | Type | Description | +| :---------- | :----- | :------------------------- | +| `key` | string | the key to decrement. | +| `decrement` | number | the amount to decrement by | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of `key` after the decrement. | If the key contains a value of the wrong type, or contains a string that cannot be represented as an integer, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 10, 0); + + const value = await redisClient.decrBy('mykey', 2); + if (value !== 8) { + throw new Error('mykey should have been 8'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-del.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-del.md new file mode 100644 index 0000000000..fa3b85f8a7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-del.md @@ -0,0 +1,54 @@ +--- +title: 'Client.del(keys)' +excerpt: '' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-del/ +--- + +Removes the specified keys. A key is ignored if it does not exist. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :------- | :------------------ | +| `keys` | string[] | the keys to delete. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with the `number` of keys that were removed. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'myvalue', 0); + + const exists = await redisClient.exists('mykey'); + if (exists === false) { + throw new Error('mykey should exist'); + } + + const value = await redisClient.get('mykey'); + console.log(`set key 'mykey' to value: ${value}`); + + await redisClient.del('mykey'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-exists.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-exists.md new file mode 100644 index 0000000000..00e37337b7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-exists.md @@ -0,0 +1,56 @@ +--- +title: 'Client.exists(keys)' +excerpt: 'Returns the number of `key` arguments that exist.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-exists/ +--- + +Returns the number of `key` arguments that exist. Note that if the same existing key is mentioned in the argument multiple times, it will be counted multiple times. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :------- | :---------------------------------- | +| `keys` | string[] | the keys to check the existence of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with the `number` of keys that exist from those specified as arguments. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + let exists = await redisClient.exists('mykey'); + if (exists === true) { + throw new Error('mykey should not exist'); + } + + await redisClient.set('mykey', 'myvalue', 0); + + exists = await redisClient.exists('mykey'); + if (exists === false) { + throw new Error('mykey should exist'); + } + + await redisClient.del('mykey'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-expire.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-expire.md new file mode 100644 index 0000000000..82dfa32d01 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-expire.md @@ -0,0 +1,51 @@ +--- +title: 'Client.expire(key, seconds)' +excerpt: 'Sets an expiration date (a timeout) on the key `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-expire/ +--- + +Sets a timeout on key, after which the key will automatically be deleted. Note that calling Expire with a non-positive timeout will result in the key being deleted rather than expired. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :--------------------------------------------- | +| `key` | string | the key to set the expiration of. | +| `seconds` | number | the value in seconds to set the expiration to. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :----------------- | :---------------------------------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with `true` if the timeout was set, and `false` if the timeout wasn't set. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'myvalue', 10); + await redisClient.expire('mykey', 100); + + const ttl = await redisClient.ttl('mykey'); + if (ttl <= 10 || ttl >= 100) { + throw new Error('mykey should have a ttl of 10 <= x < 100'); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-get.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-get.md new file mode 100644 index 0000000000..825f5f86f3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-get.md @@ -0,0 +1,54 @@ +--- +title: 'Client.get(key)' +excerpt: 'Get the value of `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-get/ +--- + +Get the key's value. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------- | +| `key` | string | the name of the key to get | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------ | :---------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of the `key`. | If the key does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'myvalue', 0) + + const exists = await redisClient.exists('mykey'); + if (exists === false) { + throw new Error('mykey should exist'); + } + + const value = await redisClient.get('mykey'); + console.log(`set key 'mykey' to value: ${value}`); + + await redisClient.del('mykey'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-getdel.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-getdel.md new file mode 100644 index 0000000000..0761a73e29 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-getdel.md @@ -0,0 +1,50 @@ +--- +title: 'Client.getDel(key)' +excerpt: 'Get the value of `key` and delete the key.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-getdel/ +--- + +Get the value of `key` and delete the key. This functionality is similar to `get`, except for the fact that it also deletes the key on success. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------ | +| `key` | string | the key to get and delete | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :-------------------------------------------------------- | :---------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of `key`. | If the key does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'oldvalue', 0); + let value = await redisClient.getSet('mykey', 'newvalue'); + + value = await redisClient.getDel('mykey'); + if (value !== 'newvalue') { + throw new Error('mykey should have been newvalue'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-getset.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-getset.md new file mode 100644 index 0000000000..46813aa37e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-getset.md @@ -0,0 +1,47 @@ +--- +title: 'Client.getSet(key, value)' +excerpt: 'Atomically sets `key` to `value` and returns the old value stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-getset/ +--- + +Atomically sets `key` to `value` and returns the value previously stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :--------------------- | +| `key` | string | the key to get and set | +| `value` | string, number, or boolean | the value to set | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the old value stored at `key`. | If `key` does not exist, or does not hold a string value, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'oldvalue', 0); + await redisClient.getSet('mykey', 'newvalue'); + await redisClient.getDel('mykey'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hdel.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hdel.md new file mode 100644 index 0000000000..c4d61066ac --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hdel.md @@ -0,0 +1,47 @@ +--- +title: 'Client.hdel(key, fields)' +excerpt: 'Deletes fields from the hash stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hdel/ +--- + +Deletes the specified fields from the hash stored at `key`. The number of fields that were removed from the hash is returned on resolution (non including non existing fields). + +### Parameters + +| Parameter | Type | Description | +| :-------- | :------- | :-------------------------------------------- | +| `key` | string | key holding the hash to delete the fields of. | +| `fields` | string[] | fields to delete from the hash. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with the number of fields that were removed from the hash, not including specified, but non existing, fields. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 'myvalue'); + await redisClient.hget('myhash', 'myfield'); + await redisClient.hdel('myhash', 'myfield'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hget.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hget.md new file mode 100644 index 0000000000..6cb26fd859 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hget.md @@ -0,0 +1,47 @@ +--- +title: 'Client.hget(key, field)' +excerpt: 'Returns the value of field in the hash stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hget/ +--- + +Returns the value associated with `field` in the hash stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :---------------------------------------- | +| `key` | string | key holding the hash to get the field of. | +| `field` | string | field to get from the hash. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :----------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value associated with `field`. | If the hash does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 'myvalue'); + await redisClient.hget('myhash', 'myfield'); + await redisClient.hdel('myhash', 'myfield'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hgetall.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hgetall.md new file mode 100644 index 0000000000..53feef5342 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hgetall.md @@ -0,0 +1,47 @@ +--- +title: 'Client.hgetall(key)' +excerpt: 'Returns all fields and values of the hash stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hgetall/ +--- + +Returns all fields and values of the hash stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the hash to get the fields of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :----------------------------- | :-------------------------------------------------------------------------------------------- | :------------ | +| `Promise<[key: string]string>` | On success, the promise resolves with the list of fields and their values stored in the hash. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 'myvalue'); + await redisClient.hset('myhash', 'myotherfield', 'myothervalue'); + const object = await redisClient.hgetall('myhash'); + console.log(`myhash has key:value pairs ${JSON.stringify(object)}`); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hincrby.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hincrby.md new file mode 100644 index 0000000000..90f7da3de6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hincrby.md @@ -0,0 +1,47 @@ +--- +title: 'Client.hincrby(key, field, increment)' +excerpt: 'Increments the value of a hash field by the given number.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hincrby/ +--- + +Increments the integer value of `field` in the hash stored at `key` by `increment`. If `key` does not exist, a new key holding a hash is created. If `field` does not exist the value is set to 0 before the operation is set to 0 before the operation is performed. + +### Parameters + +| Parameter | Type | Description | +| :---------- | :----- | :---------------------------------------------- | +| `key` | string | key holding the hash to increment the field of. | +| `field` | string | field to increment in the hash. | +| `increment` | number | amount to increment the field by. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with the value at `field` after the increment operation. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 10); + await redisClient.hincrby('myhash', 'myfield', 20); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hkeys.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hkeys.md new file mode 100644 index 0000000000..240d29cb02 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hkeys.md @@ -0,0 +1,52 @@ +--- +title: 'Client.hkeys(key)' +excerpt: 'Returns all fields of the hash stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hkeys/ +--- + +Returns all fields of the hash stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the hash to get the fields of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :------------------ | :-------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the list of fields in the hash. | If the hash does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 'myvalue'); + await redisClient.hset('myhash', 'myotherfield', 'myothervalue'); + + const keys = await redisClient.hkeys('myhash'); + if (keys.length !== 2) { + throw new Error('myhash should have 2 keys'); + } + + console.log(`myhash has keys ${keys}`); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hlen.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hlen.md new file mode 100644 index 0000000000..ac241a9098 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hlen.md @@ -0,0 +1,46 @@ +--- +title: 'Client.hlen(key)' +excerpt: 'Returns the number of fields in the hash stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hlen/ +--- + +Returns the number of fields in the hash stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the hash to get the fields of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the number of fields in the hash. | If the hash does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 10); + await redisClient.hset('myhash', 'myotherfield', 20); + await redisClient.hlen('myhash'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hset.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hset.md new file mode 100644 index 0000000000..053c279510 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hset.md @@ -0,0 +1,48 @@ +--- +title: 'Client.hset(key, field, value)' +excerpt: 'Sets the value of field in the hash stored at `key` to `value`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hset/ +--- + +Sets the specified field in the hash stored at `key` to `value`. If the `key` does not exist, a new key holding a hash is created. If `field` already exists in the hash, it is overwritten. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :---------------------------------------- | +| `key` | string | key holding the hash to set the field of. | +| `field` | string | field to set in the hash. | +| `value` | string | value to set the field to. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :-------------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the number of fields that were added. | If the hash does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 'myvalue'); + await redisClient.hget('myhash', 'myfield'); + await redisClient.hdel('myhash', 'myfield'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hsetnx.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hsetnx.md new file mode 100644 index 0000000000..4ac7ae8bd9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hsetnx.md @@ -0,0 +1,52 @@ +--- +title: 'Client.hsetnx(key, field, value)' +excerpt: 'Sets the value of field in the hash stored at `key` to `value` only if field does not exist in the hash.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hsetnx/ +--- + +Sets the specified field in the hash stored at `key` to `value`, only if `field` does not yet exist. If `key` does not exist, a new key holding a hash is created. If `field` already exists, this operation has no effect. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :---------------------------------------- | +| `key` | string | key holding the hash to set the field of. | +| `field` | string | field to set in the hash. | +| `value` | string | value to set the field to. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------ | +| `Promise` | On success, the promise resolves with `1` if `field` is a new field in the hash and value was set, and with `0` if `field` already exists in the hash and no operation was performed. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hsetnx('myhash', 'myfield', 'myvalue') + await redisClient.hsetnx('myhash', 'myotherfield', 'myothervalue'); + + const set = await redisClient.hsetnx('myhash', 'myfield', 'mynewvalue'); + if (set === true) { + throw new Error('hsetnx should have failed on existing field'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hvals.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hvals.md new file mode 100644 index 0000000000..fb63b24f52 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-hvals.md @@ -0,0 +1,52 @@ +--- +title: 'Client.hvals(key)' +excerpt: 'Returns all values of the hash stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-hvals/ +--- + +Returns all values of the hash stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the hash to get the fields of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :------------------ | :-------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the list of values in the hash. | If the hash does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.hset('myhash', 'myfield', 'myvalue'); + await redisClient.hset('myhash', 'myotherfield', 'myothervalue'); + + const values = await redisClient.hvals('myhash'); + if (values.length !== 2) { + throw new Error('myhash should have 2 values'); + } + + console.log(`myhash has values ${values}`); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-incr.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-incr.md new file mode 100644 index 0000000000..992192a384 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-incr.md @@ -0,0 +1,52 @@ +--- +title: 'Client.incr(key)' +excerpt: 'Increments the number stored at `key` by one.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-incr/ +--- + +Increments the number stored at `key` by one. If the key does not exist, it is set to zero before performing the operation. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------- | +| `key` | string | the key to increment | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of `key` after the increment. | If the key contains a value of the wrong type, or contains a string that cannot be represented as an integer, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 10, 0); + + let value = await redisClient.incr('mykey'); + value = await redisClient.incrBy('mykey', value); + value = await redisClient.decrBy('mykey', value); + value = await redisClient.decr('mykey'); + if (value !== -1) { + throw new Error('mykey should have been -1'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-incrby.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-incrby.md new file mode 100644 index 0000000000..10a89d5a8b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-incrby.md @@ -0,0 +1,53 @@ +--- +title: 'Client.incrBy(key, increment)' +excerpt: 'Increments the number stored at `key` by `increment`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-incrby/ +--- + +Increments the number stored at `key` by `increment`. If the key does not exist, it is set to zero before performing the operation. + +### Parameters + +| Parameter | Type | Description | +| :---------- | :----- | :------------------------- | +| `key` | string | the key to increment | +| `increment` | number | the amount to increment by | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of `key` after the increment. | If the key contains a value of the wrong type, or contains a string that cannot be represented as an integer, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 10, 0); + + let value = await redisClient.incr('mykey'); + value = await redisClient.incrBy('mykey', value); + value = await redisClient.decrBy('mykey', value); + value = await redisClient.decr('mykey'); + if (value !== -1) { + throw new Error('mykey should have been -1'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lindex.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lindex.md new file mode 100644 index 0000000000..9790f4cf20 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lindex.md @@ -0,0 +1,53 @@ +--- +title: 'Client.lindex(key)' +excerpt: 'Returns the element at index `index` of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-lindex/ +--- + +Returns the specified element of the list stored at `key`. The index is zero-based. Negative indices can be used to designate elements starting at the tail of the list. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------------------------ | +| `key` | string | key holding the list to get the element of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :----------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | +| `Promise` | On success, the promise resolves with the requested element. | If the list does not exist, or the index is out of bounds, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.rpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + await redisClient.rpush('mylist', 'third'); + + const item = await redisClient.lindex('mylist', 0); + if (item !== 'first') { + throw new Error('lindex operation should have returned first'); + } + + await redisClient.lrange('mylist', 1, 2); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-llen.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-llen.md new file mode 100644 index 0000000000..fee1c521af --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-llen.md @@ -0,0 +1,53 @@ +--- +title: 'Client.llen(key)' +excerpt: 'Returns the length of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-llen/ +--- + +Returns the length of the list stored at `key`. If `key` does not exist, it is interpreted as an empty list and 0 is returned. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the list to get the length of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :--------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the length of the list at `key`. | If the list does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default function () { + redisClient + .rpush('mylist', 'first') + .then((_) => redisClient.rpush('mylist', 'second')) + .then((_) => redisClient.rpush('mylist', 'third')) + .then((_) => redisClient.llen('mylist')) + .then((length) => { + if (length !== 3) { + throw new Error('llen operations should have returned 3'); + } + }); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lpop.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lpop.md new file mode 100644 index 0000000000..437101a803 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lpop.md @@ -0,0 +1,49 @@ +--- +title: 'Client.lpop(key)' +excerpt: 'Removes and returns the first element of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-lpop/ +--- + +Removes and returns the first element of the list stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------------------- | +| `key` | string | key holding the list to left pop from. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :-------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of the first element. | If the list does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.lpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + + const item = await redisClient.lpop('mylist'); + await redisClient.rpush('mylist', item); + await redisClient.rpop('mylist'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lpush.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lpush.md new file mode 100644 index 0000000000..b8b7d8f5d5 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lpush.md @@ -0,0 +1,50 @@ +--- +title: 'Client.lpush(key, values)' +excerpt: 'Adds the string `value` to the left of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-lpush/ +--- + +Inserts all the specified values at the head of the list stored at `key`. If `key` does not exist, it is created as empty list before performing the push operations. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------------------ | +| `key` | string | key holding the list to left push to. | +| `values` | a variadic array of strings, numbers, or booleans | values to push to the list. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :--------------------------------------------------------------------------- | :---------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the length of the list after the push. | When `key` holds a value that is not a list, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.lpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + + let item = await redisClient.lpop('mylist'); + item = redisClient.rpush('mylist', item); + item = redisClient.rpop('mylist'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lrange.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lrange.md new file mode 100644 index 0000000000..c7f991233b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lrange.md @@ -0,0 +1,55 @@ +--- +title: 'Client.lrange(key, start, stop)' +excerpt: 'Returns the specified elements of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-lrange/ +--- + +Returns the specified elements of the list stored at `key`. The offsets start and stop are zero-based indexes. These offsets can be negative numbers, where they indicate offsets starting at the end of the list. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :---------------------------------------- | +| `key` | string | key holding the list to get the range of. | +| `start` | number | index of the first element to return. | +| `stop` | number | index of the last element to return. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :------------------ | :--------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with the list of elements in the specified range. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.rpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + await redisClient.rpush('mylist', 'third'); + + const item = redisClient.lindex('mylist', 0); + if (item !== 'first') { + throw new Error('lindex operation should have returned first'); + } + + await redisClient.lrange('mylist', 1, 2); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lrem.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lrem.md new file mode 100644 index 0000000000..b92b8dd139 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lrem.md @@ -0,0 +1,57 @@ +--- +title: 'Client.lrem(key, count, value)' +excerpt: 'Removes the first count occurrences of elements equal to value from the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-lrem/ +--- + +Removes the first `count` occurrences of `value` from the list stored at `key`. If `count` is positive, elements are removed from the beginning of the list. If `count` is negative, elements are removed from the end of the list. If `count` is zero, all elements matching `value` are removed. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :---------------------------------------------- | +| `key` | string | key holding the list to remove the elements of. | +| `count` | number | number of elements to remove. | +| `value` | string | value to remove from the list. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :-------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the number of removed elements. | If the list does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.rpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + await redisClient.rpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + await redisClient.lrem('mylist', 0, 'second'); + + const length = await redisClient.lrem('mylist', 1, 'first'); + if (length !== 1) { + throw new Error('lrem operations should have left 1 item behind'); + } + + await redisClient.lpop('mylist'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lset.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lset.md new file mode 100644 index 0000000000..648cd6f8b6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-lset.md @@ -0,0 +1,50 @@ +--- +title: 'Client.lset(key, index, element)' +excerpt: 'Sets the list element at index `index` of the list stored at `key` to `value`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-lset/ +--- + +Sets the list element at `index` to `element`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------------------------ | +| `key` | string | key holding the list to set the element of. | +| `index` | number | index of the element to set. | +| `element` | string | value to set the element to. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------ | :------------------------------------------------------------------------------------------------ | +| `Promise` | On success, the promise resolves with `OK`. | If the list does not exist, or the index is out of bounds, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.rpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + await redisClient.rpush('mylist', 'third'); + await redisClient.lset('mylist', 0, 1); + await redisClient.lset('mylist', 1, 2); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-mget.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-mget.md new file mode 100644 index 0000000000..974ec2c9c4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-mget.md @@ -0,0 +1,49 @@ +--- +title: 'Client.mget(keys)' +excerpt: 'Returns the values of all specified keys.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-mget/ +--- + +Returns the values of all specified keys. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :------- | :----------------------------- | +| `keys` | string[] | the keys to get the values of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with the list of values at the specified keys. For every key that does not hold a string value, or does not exist, the value `null` will be returned. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('first', 1, 0) + await redisClient.set('second', 2, 0); + await redisClient.set('third', 3, 0); + + const values = await redisClient.mget('first', 'second', 'third'); + console.log(`set values are: ${values}`); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-persist.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-persist.md new file mode 100644 index 0000000000..cb9c85fa9c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-persist.md @@ -0,0 +1,52 @@ +--- +title: 'Client.persist(key)' +excerpt: 'Remove the expiration from a key.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-persist/ +--- + +Removes the existing timeout on `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :-------------------------------- | +| `key` | string | the key to remove the timeout of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :----------------- | :------------------------------------------------------------------------------------------ | :------------ | +| `Promise` | On success, the promise resolves with `true` if the timeout was removed, `false` otherwise. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'myvalue', 10) + await redisClient.expire('mykey', 100); + + const ttl = await redisClient.ttl('mykey'); + if (ttl <= 10) { + throw new Error('mykey should have a ttl of 10 <= x < 100'); + } + + await redisClient.persist('mykey', 100); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-randomkey.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-randomkey.md new file mode 100644 index 0000000000..e2571bb35e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-randomkey.md @@ -0,0 +1,42 @@ +--- +title: 'Client.randomKey()' +excerpt: 'Returns a random key from the keyspace.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-randomkey/ +--- + +Returns a random key. + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :--------------------------------------------------------- | :--------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the random key name. | If the database is empty, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('first', 1, 0); + await redisClient.set('second', 2, 0); + await redisClient.set('third', 3, 0); + + const key = await redisClient.randomKey(); + console.log(`picked random key is: ${key}`); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-rpop.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-rpop.md new file mode 100644 index 0000000000..e49eea7803 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-rpop.md @@ -0,0 +1,49 @@ +--- +title: 'Client.rpop(key)' +excerpt: 'Removes and returns the last element of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-rpop/ +--- + +Removes and returns the last element of the list stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :-------------------------------------- | +| `key` | string | key holding the list to right pop from. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :-------------------------------------------------------------------- | :----------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the value of the first element. | If the list does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.lpush('mylist', 'first') + await redisClient.rpush('mylist', 'second'); + + const item = await redisClient.lpop('mylist'); + await redisClient.rpush('mylist', item); + await redisClient.rpop('mylist'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-rpush.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-rpush.md new file mode 100644 index 0000000000..5f543cb7de --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-rpush.md @@ -0,0 +1,50 @@ +--- +title: 'Client.rpush(key, values)' +excerpt: 'Adds the string `value` to the right of the list stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-rpush/ +--- + +Inserts all the specified values at the tail of the list stored at `key`. If `key` does not exist, it is created as empty list before performing the push operation. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------------------- | +| `key` | string | key holding the list to right push to. | +| `values` | a variadic array of strings, numbers, or booleans | values to push to the list. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the length of the list after the push operation. | When `key` holds a value that is not a list, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.lpush('mylist', 'first'); + await redisClient.rpush('mylist', 'second'); + + const item = await redisClient.lpop('mylist'); + await redisClient.rpush('mylist', item); + await redisClient.rpop('mylist'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sadd.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sadd.md new file mode 100644 index 0000000000..fd2c95c11a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sadd.md @@ -0,0 +1,51 @@ +--- +title: 'Client.sadd(key, members)' +excerpt: 'Adds the specified members to the set stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-sadd/ +--- + +Adds the specified members to the set stored at `key`. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the set to add the members to. | +| `members` | a variadic array of strings, numbers, or booleans | members to add to the set. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | +| `Promise` | On success, the promise resolves with the number of elements that were added to the set, not including elements already present in the set. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.sadd('myset', 'foo'); + await redisClient.sadd('myset', 'bar'); + + const isit = await redisClient.sismember('myset', 'foo'); + if (isit === false) { + throw new Error('sismember should have returned true'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sendCommand.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sendCommand.md new file mode 100644 index 0000000000..6f6015fc9e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sendCommand.md @@ -0,0 +1,48 @@ +--- +title: 'Client.sendCommand(command, args)' +excerpt: 'Issue a command to the Redis server.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-sendcommand/ +--- + +In the event a Redis command you wish to use is not implemented yet, the `sendCommand` method can be used to send a custom commands to the server. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------------------------------------------------------------------------------------------- | +| `command` | string | command name to issue to the Redis server, as described in [Redis' documentation](https://redis.io/commands/). | +| `args` | a variadic array of strings, numbers, or booleans | command arguments to pass to the Redis server. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :------------- | :------------------------------------------------------------------------------------------- | :------------ | +| `Promise` | On success, the promise resolves with string, number, or boolean result the server would reply to the command sent. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + const result = await redisClient.sendCommand('ECHO', 'Hello world'); + if (result !== 'Hello world') { + throw new Error('ECHO should have returned "Hello world"'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-set.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-set.md new file mode 100644 index 0000000000..6fa656b9e3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-set.md @@ -0,0 +1,56 @@ +--- +title: 'Client.set(key, value, expiration)' +excerpt: 'Set `key` to hold `value`, with a time to live equal to `expiration`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-set/ +--- + +Set the value of a key, with a time to live equal to the expiration time parameter (in seconds). If the key already holds a value, it is overwritten. + +### Parameters + +| Parameter | Type | Description | +| :----------- | :------ | :------------------------------------------------------------------ | +| `key` | string | the key to set | +| `value` | string, number, or boolean | the value to set | +| `expiration` | integer | the time to live in seconds. the `0` value indicates no expiration. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------ | :----------------------------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with 'OK'. | If the provided `value` is not of a supported type, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'myvalue', 0); + + const exists = await redisClient.exists('mykey'); + if (exists === false) { + throw new Error('mykey should exist'); + } + + const value = await redisClient.get('mykey'); + console.log(`set key 'mykey' to value: ${value}`) + + await redisClient.del('mykey'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sismember.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sismember.md new file mode 100644 index 0000000000..69f52e14d3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-sismember.md @@ -0,0 +1,51 @@ +--- +title: 'Client.sismember(key, member)' +excerpt: 'Determines if a given value is a member of the set stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-sismember/ +--- + +Returns if member is a member of the set stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :--------------------------------------------------------- | +| `key` | string | key holding the set to check if the member is a member of. | +| `member` | string, number, or boolean | member to check if is a member of the set. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :----------------- | :------------------------------------------------------------------------------------------------------------- | :------- | +| `Promise` | On success, the promise resolves with `true` if the element is a member of the set, `false` otherwise. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.sadd('myset', 'foo'); + await redisClient.sadd('myset', 'bar'); + + const isit = await redisClient.sismember('myset', 'foo'); + if (isit === false) { + throw new Error('sismember should have returned true'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-smembers.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-smembers.md new file mode 100644 index 0000000000..0bc3ed8b23 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-smembers.md @@ -0,0 +1,51 @@ +--- +title: 'Client.smembers(key)' +excerpt: 'Returns all the members of the set stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-smembers/ +--- + +Returns all the members of the set values stored at `keys`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------- | +| `key` | string | key holding the set to get the members of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :------------------ | :----------------------------------------------------------------------------------------------- | :------- | +| `Promise` | On success, the promise resolves with an array containing the values present in the set. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.sadd('myset', 'foo'); + await redisClient.sadd('myset', 'bar'); + await redisClient.sadd('myset', 'foo'); + + const members = await redisClient.smembers('myset'); + if (members.length !== 2) { + throw new Error('sismember should have length 2'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-spop.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-spop.md new file mode 100644 index 0000000000..b7a169df2b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-spop.md @@ -0,0 +1,50 @@ +--- +title: 'Client.spop(key)' +excerpt: 'Removes and returns a random member of the set stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-spop/ +--- + +Removes and returns a random element from the set value stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :--------------------------------------------- | +| `key` | string | key holding the set to get a random member of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------------- | :-------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves to the returned set member. | If the set does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.sadd('myset', 'foo') + await redisClient.sadd('myset', 'bar'); + await redisClient.spop('myset', 'foo'); + const members = await redisClient.smembers('myset'); + if (members.length !== 1) { + throw new Error('sismember should have length 1'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-srandmember.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-srandmember.md new file mode 100644 index 0000000000..61ab89f048 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-srandmember.md @@ -0,0 +1,51 @@ +--- +title: 'Client.srandmember(key)' +excerpt: 'Returns a random member of the set stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-srandmember/ +--- + +Returns a random element from the set value stored at `key`. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :--------------------------------------------- | +| `key` | string | key holding the set to get a random member of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------------------ | :-------------------------------------------------------------------- | +| `Promise` | On success, the promise resolves with the selected random member. | If the set does not exist, the promise is rejected with an error. | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.sadd('myset', 'foo'); + await redisClient.sadd('myset', 'bar'); + await redisClient.spop('myset', 'foo'); + + const members = await redisClient.smembers('myset'); + if (members.length !== 1) { + throw new Error('sismember should have length 1'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-srem.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-srem.md new file mode 100644 index 0000000000..89e4a21781 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-srem.md @@ -0,0 +1,52 @@ +--- +title: 'Client.srem(key, members)' +excerpt: 'Removes the specified members from the set stored at `key`.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-srem/ +--- + +Removes the specified members from the set stored at `key`. Specified members that are not a member of this set are ignored. If key does not exist, it is treated as an empty set and this command returns 0. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :---------------------------------------------- | +| `key` | string | key holding the set to remove the members from. | +| `members` | a variadic array of strings, numbers, or booleans | members to remove from the set. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------- | :------- | +| `Promise` | On success, the promise resolves with the number of members that were remove from the set, not including non existing members. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.sadd('myset', 'foo'); + await redisClient.sadd('myset', 'bar'); + await redisClient.srem('myset', 'foo'); + + const members = await redisClient.smembers('myset'); + if (members.length !== 1) { + throw new Error('sismember should have length 1'); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-ttl.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-ttl.md new file mode 100644 index 0000000000..6508869b55 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/10 Client/Client-ttl.md @@ -0,0 +1,52 @@ +--- +title: 'Client.ttl(key)' +excerpt: 'Returns the remaining time to live of a key.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/client/client-ttl/ +--- + +Returns the remaining time to live of a key that has a timeout. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :----- | :------------------------- | +| key | string | the key to get the TTL of. | + + +### Returns + +| Type | Resolves with | Rejected when | +| :---------------- | :---------------------------------------------------------------------- | :------- | +| `Promise` | On success, the promise resolves with the TTL value in seconds. | | + +### Example + + + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default async function () { + await redisClient.set('mykey', 'myvalue', 10); + await redisClient.expire('mykey', 100); + + const ttl = await redisClient.ttl('mykey'); + if (ttl <= 10) { + throw new Error('mykey should have a ttl of 10 <= x < 100'); + } + + await redisClient.persist('mykey', 100); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/20 Redis options.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/20 Redis options.md new file mode 100644 index 0000000000..00f22d72f3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/02 redis/20 Redis options.md @@ -0,0 +1,54 @@ +--- +title: 'Redis options' +slug: '/javascript-api/k6-experimental/redis/options/' +excerpt: 'Options allow to fine tune how a Redis client behaves and interacts with a Redis server or cluster.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/redis-options/ +--- + +You can configure the [Redis Client](/javascript-api/k6-experimental/redis/client) at construction time with the [Options](#options) object. +We recommend passing the options to the constructor as an argument, then passing the most common options, such as the `addrs` and `password`, to the constructor from the environment. + +The following snippet provides an example: + +```javascript +import redis from 'k6/experimental/redis'; + +// Get the redis instance(s) address and password from the environment +const redis_addrs = __ENV.REDIS_ADDRS || ''; +const redis_password = __ENV.REDIS_PASSWORD || ''; + +// Instantiate a new redis client +const redisClient = new redis.Client({ + addrs: redis_addrs.split(',') || new Array('localhost:6379'), // in the form of 'host:port', separated by commas + password: redis_password, +}); + +export default function () { + // do something with the redis client +} +``` + +## Options + +| Option name | type | default | description | +| :------------------- | :---------------- | :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `addrs` | string[] | | Array of addresses in the 'host:port' defining which connect Redis to connect to. Supplying a single entry would connect the client to a single Redis instance. Supplying multiple entries would connect the client to a cluster/sentinel nodes. | +| `db` | number (optional) | 0 | The id of the database to be selected after connecting to the server. Only used when connecting to a single-node use. | +| `username` | string (optional) | | Username to authenticate the client connection with. | +| `password` | string (optional) | | Password to authenticate the client connection with. | +| `sentinelUsername` | string (optional) | | Username to authenticate the client connection with when connecting to a sentinel. | +| `sentinelPassword` | string (optional) | | Password to authenticate the client connection with when connecting to a sentinel. | +| `masterName` | string (optional) | | The name of the master to connect to when connecting to a Redis cluster. | +| `maxRetries` | number (optional) | 0 | The maximum number of retries to attempt when connecting to a Redis server before giving up. | +| `minRetryBackoff` | number (optional) | 8 (ms) | The minimum amount of time to wait between retries when connecting to a Redis server. | +| `maxRetryBackoff` | number (optional) | 512 (ms) | The maximum amount of time to wait between retries when connecting to a Redis server. | +| `dialTimeout` | number (optional) | 5 (seconds) | The maximum amount of time to wait for a connection to a Redis server to be established. | +| `readTimeout` | number (optional) | 3 (seconds) | The maximum amount of time to wait for socket reads to succeed. Use `-1` for no timeout. | +| `writeTimeout` | number (optional) | `readTimeout` | The maximum amount of time to wait for a socket write to succeed. Use `-1` for no timeout. | +| `poolSize` | number (optional) | 10 (per CPU) | The maximum number of socket connections to keep open in the connection pool. | +| `minIdleConns` | number (optional) | | The minimum number of idle connections to keep open in the connection pool. | +| `maxIdleConns` | number (optional) | | The maximum number of idle connections to keep open in the connection pool. | +| `maxConnAge` | number (optional) | 0 | The maximum amount of time a connection can be idle in the connection pool before being closed. | +| `poolTimeout` | number (optional) | `readTimeout + 1` | The maximum amount of time to wait for a connection to the Redis server to be returned from the pool. | +| `idleTimeout` | number (optional) | `readTimeout + 1` | The maximum amount of time the client waits for a connection to become active before timing out. | +| `idleCheckFrequency` | number (optional) | 1 (minute) | The frequency at which the client checks for idle connections in the connection pool. Use `-1` to disable the checks. | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/03 timers.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/03 timers.md new file mode 100644 index 0000000000..d9e6b98cd7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/03 timers.md @@ -0,0 +1,17 @@ +--- +title: "timers" +excerpt: "k6 timers experimental API" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/timers/ +--- + + + + +This modules implements the commonly found in browsers: + +| Function | Description | +| :------------------------------------------ | :--------------------------------------------------------------------------------------------- | +| [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) | sets a function to be run after a given timeout | +| [clearTimeout](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) | clears a previously set timeout with `setTimeout` | +| [setInterval](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) | sets a function to be run on a given interval | +| [clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) | clears a previously set interval with `setInterval` | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing.md new file mode 100644 index 0000000000..22559bdb88 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing.md @@ -0,0 +1,62 @@ +--- +title: "tracing" +excerpt: "k6 Tracing experimental API" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/tracing/ +--- + + + + +With this experimental module, you can _instrument_ HTTP requests so that they emit traces as the test runs. + +## About trace contexts + +A _trace context_ is a set of standardized HTTP headers added to a request that lets a tracing system correlate the request with other requests as they navigate through a system. The trace context specifications, such as the supported [W3C Trace Context](https://www.w3.org/TR/trace-context/) and [Jaeger Trace Context](https://www.jaegertracing.io/docs/1.21/client-libraries/#propagation-format), define specific header names and an encoding format for the header values. + +A trace context generally consists of, at least, a `trace_id`, a `span_id`, and a `sampled` flag. The `trace_id` is a unique identifier for the trace, the `span_id` is a unique identifier for the request, and the `sampled` flag is a boolean that indicates whether the request should be traced. For instance, the [W3C Trace Context](https://www.w3.org/TR/trace-context/) defines the `Traceparent` header, whose value contains a `trace_id`, a `span_id` and a `sampled` flag, encoded as a dash (`-`) separated list of hexadecimal values. When a trace context header is attached to an HTTP request, we refer to it as being _propagated_ to the downstream service. + +## API + +| Class/Function | Description | +| :----------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------ | +| [instrumentHTTP](/javascript-api/k6-experimental/tracing/instrumenthttp) | instruments the k6 http module with tracing capabilities. | +| [Client](/javascript-api/k6-experimental/tracing/client) | configurable Client that exposes instrumented HTTP operations and allows selectively instrumenting requests with tracing. | + +## Example + +This example demonstrates how to use the tracing API to instrument every HTTP request made in a script with tracing information. + + + +```javascript +import { check } from "k6"; +import tracing from "k6/experimental/tracing"; +import http from "k6/http"; + +// instrumentHTTP will ensure that all requests made by the http module +// from this point forward will have a trace context attached. +// +// The first argument is a configuration object that +// can be used to configure the tracer. +tracing.instrumentHTTP({ + // possible values: "w3c", "jaeger" + propagator: "w3c", +}); + +export default () => { + // the instrumentHTTP call in the init context replaced + // the http module with a version that will automatically + // attach a trace context to every request. + // + // Because the instrumentHTTP call was configured with the + // w3c trace propagator, this request will as a result have + // a `traceparent` header attached. + const res = http.get("http://httpbin.org/get", { + headers: { + "X-Example-Header": "instrumented/get", + }, + }); +}; +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/01 instrumentHTTP.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/01 instrumentHTTP.md new file mode 100644 index 0000000000..740988d82c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/01 instrumentHTTP.md @@ -0,0 +1,53 @@ +--- +title: 'instrumentHTTP' +excerpt: 'instrumentHTTP instruments the k6 http module with tracing capabilities.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/tracing/instrumenthttp/ +--- + +The `instrumentHTTP` function instruments the k6 http module with tracing capabilities. It transparently replaces each of the k6 http module functions with versions that automatically attach a trace context to every request. Instrumented functions include [del](/javascript-api/k6-http/del), [get](/javascript-api/k6-http/get), [head](/javascript-api/k6-http/head), [options](/javascript-api/k6-http/options), [patch](/javascript-api/k6-http/patch), [post](/javascript-api/k6-http/post), [put](/javascript-api/k6-http/head), and [request](/javascript-api/k6-http/request). + +The `instrumentHTTP` automatically adds tracing information to HTTP requests performed using the `k6/http` module functions (mentioned above). +This means that, to instrument the HTTP requests, you don't need to rewrite any code. +Instead, call it once in the init context. +From that point forward, all requests made by the HTTP module from that point forward will have a trace context header added to them, and the metadata for the data-point output will have the used `trace_id`. For details about propagation, refer to [About trace contexts](/javascript-api/k6-experimental/tracing#about-trace-contexts). + +## Parameters + +| Name | Type | Description | +| :-------- | :----------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------- | +| `options` | [`Options`](/javascript-api/k6-experimental/tracing/options) | Configures the tracing behavior with the provided [`Options`](/javascript-api/k6-experimental/tracing/options) object. | + +## Example + +This example demonstrates how calling the `instrumentHTTP` function in the init context of a script once ensures that all requests made by the HTTP module from that point forward will have a trace context header attached. + + + +```javascript +import { check } from "k6"; +import tracing from "k6/experimental/tracing"; +import http from "k6/http"; + +// instrumentHTTP will ensure that all requests made by the http module +// will be traced. The first argument is a configuration object that +// can be used to configure the tracer. +// +// Currently supported HTTP methods are: get, post, put, patch, head, +// del, options, and request. +tracing.instrumentHTTP({ + // propagator defines the trace context propagation format. + // Currently supported: w3c and jaeger. + // Default: w3c + propagator: "w3c", +}); + +export default () => { + const res = http.get("http://httpbin.org/get", { + headers: { + "X-Example-Header": "instrumented/get", + }, + }); +}; +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/02 Client.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/02 Client.md new file mode 100644 index 0000000000..9df7e75b8e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/02 Client.md @@ -0,0 +1,87 @@ +--- +title: 'Client' +excerpt: 'Client is a HTTP client attaching tracing information to its requests.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/tracing/client/ +--- + +`Client` is an HTTP client constructor that attaches tracing information to its requests. Use it to include a tracing context in HTTP requests so that tracing backends (such as [Grafana Tempo](https://grafana.com/oss/tempo/)) can incorporate their results. + + The `Client` class acts as a drop-in replacement for the standard `http` module and attaches a [trace context](https://www.w3.org/TR/trace-context/) to the requests headers, and add a `trace_id` to HTTP-related k6 output's data points metadata. It currently supports the [W3C Trace Context](https://www.w3.org/TR/trace-context/) and [Jaeger](https://www.jaegertracing.io/docs/1.21/client-libraries/#propagation-format) trace context propagation formats. For details about propagation, refer to [About trace contexts](/javascript-api/k6-experimental/tracing#about-trace-contexts). + +The `Client` constructor accepts an [`Options`](/javascript-api/k6-experimental/tracing/options) object as its only parameter. + +## Example + +This example demonstrates how to instantiate a tracing client and use it to instrument HTTP calls with trace context headers. It also illustrates how you can use it alongside the standard `http` module to perform non-instrumented HTTP calls. + + + + +```javascript +import { check } from "k6"; +import tracing from "k6/experimental/tracing"; +import http from "k6/http"; + +// Explicitly instantiating a tracing client allows to distringuish +// instrumented from non-instrumented HTTP calls, by keeping APIs separate. +// It also allows for finer-grained configuration control, by letting +// users changing the tracing configuration on the fly during their +// script's execution. +const instrumentedHTTP = new tracing.Client({ + propagator: "w3c", +}); + +const testData = { name: "Bert" }; + +export default () => { + // Using the tracing client instance, HTTP calls will have + // their trace context headers set. + let res = instrumentedHTTP.request("GET", "http://httpbin.org/get", null, { + headers: { + "X-Example-Header": "instrumented/request", + }, + }); + + // The tracing client offers more flexibility over + // the `instrumentHTTP` function, as it leaves the + // imported standard http module untouched. Thus, + // one can still perform non-instrumented HTTP calls + // using it. + res = http.post("http://httpbin.org/post", JSON.stringify(testData), { + headers: { "X-Example-Header": "noninstrumented/post" }, + }); + + res = instrumentedHTTP.del("http://httpbin.org/delete", null, { + headers: { "X-Example-Header": "instrumented/delete" }, + }); +}; + +``` + + + + +## HTTP module functions equivalents + +The `Client` class exposes the same API as the standard `http` module. Except for the `batch` method, which is absent from `Client`. The following table lists the `Client` methods which have an equivalent in the standard `http` module: + +| Method | HTTP equivalent | Description | +| :---------------------------------------------- | :------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Client.del(url, [body], [params])` | [http.del](/javascript-api/k6-http/del) | Performs an instrumented HTTP DELETE request. The method has the same prototype as the `http.del` function and should transparently act as a drop-in replacement for it. | +| `Client.get(url, [params])` | [http.get](/javascript-api/k6-http/get) | Performs an instrumented HTTP GET request. The method has the same prototype as the `http.get` function and should transparently act as a drop-in replacement for it. | +| `Client.head(url, [params])` | [http.head](/javascript-api/k6-http/head) | Performs an instrumented HTTP HEAD request. The method has the same prototype as the `http.head` function and should transparently act as a drop-in replacement for it. | +| `Client.options(url, [body], [params])` | [http.options](/javascript-api/k6-http/options) | Performs an instrumented HTTP OPTIONS request. The method has the same prototype as the `http.options` function and should transparently act as a drop-in replacement for it. | +| `Client.patch(url, [body], [params])` | [http.patch](/javascript-api/k6-http/patch) | Performs an instrumented HTTP PATCH request. The method has the same prototype as the `http.patch` function and should transparently act as a drop-in replacement for it. | +| `Client.post(url, [body], [params])` | [http.post](/javascript-api/k6-http/post) | Performs an instrumented HTTP POST request. The method has the same prototype as the `http.post` function and should transparently act as a drop-in replacement for it. | +| `Client.put(url, [body], [params])` | [http.put](/javascript-api/k6-http/head) | Performs an instrumented HTTP HEAD request. The method has the same prototype as the `http.put` function and should transparently act as a drop-in replacement for it. | +| `Client.request(method, url, [body], [params])` | [http.request](/javascript-api/k6-http/request) | Performs an instrumented HTTP request. The method has the same prototype as the `http.request` function and should transparently act as a drop-in replacement for it. | +| `Client.asyncRequest(method, url, [body], [params])` | [http.asyncRequest](/javascript-api/k6-http/asyncrequest) | Performs an instrumented HTTP asynchronous request. The method has the same prototype as the `http.asyncRequest` function and should transparently act as a drop-in replacement for it. | + + +## Configuration + +`Client` instances support being reconfigured using the following API: + +| Method | Description | +| :-------------------------- | :---------------------------------------------------------------------------------------------------------------------- | +| `Client.configure(options)` | Reconfigures the tracing client instance with the provided [`Options`](/javascript-api/k6-experimental/tracing/options) | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/03 Options.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/03 Options.md new file mode 100644 index 0000000000..35444f1618 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/04 tracing/03 Options.md @@ -0,0 +1,13 @@ +--- +title: 'Options' +excerpt: 'Options allows to configure the tracing instrumentation behavior.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/tracing/options/ +--- + +Use the `Options` object to configure the tracing instrumentation behavior. It is used during the instantiation of a [`Client`](/javascript-api/k6-experimental/tracing/client) instance and also as a parameter to the [`instrumentHTTP`](/javascript-api/k6-experimental/tracing/instrumenthttp) function. It controls the general behavior of the tracing instrumentation and is unspecific to any particular tracing client instance. + +## Options + +| Option name | Type | Default | Description | +| :----------- | :------- | :------ | :----------------------------------------------------------------------------- | +| `propagator` | `string` | `w3c` | The trace context propagation format. Currently supported: `w3c` and `jaeger`. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets.md new file mode 100644 index 0000000000..fd484c69f3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets.md @@ -0,0 +1,118 @@ +--- +title: 'websockets' +excerpt: "k6 websockets experimental API" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/ +--- + + + +This experimental API implements the browser [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) with additional k6-specific functionalities (cookies, tags, headers and so on). + +The main difference between this module and [`k6/ws`](/javascript-api/k6-ws/) is that this module uses a global event loop instead of a local one. +A global event loop lets a single VU have multiple concurrent connections, which improves performance. + +The `WebSocket API` is not fully implemented, and we're working on it, but we believe it's usable for most users. So whether you're writing a new WebSocket test, or currently using the `k6/ws` module, we invite you to give it a try, and report any issues in the project's [issue tracker](https://github.com/grafana/xk6-websockets/). Our midterm goal is to make this module part of k6 core, and long-term to replace the [`k6/ws`](/javascript-api/k6-ws/) module. + + +| Class/Method | Description | +| ------------ | ----------- | +| [Params](/javascript-api/k6-experimental/websockets/params/) | Used for setting various WebSocket connection parameters such as headers, cookie jar, compression, etc. | +| [WebSocket(url, protocols, params)](/javascript-api/k6-experimental/websockets/websocket) | Constructs a new WebSocket connection. | +| [WebSocket.close()](/javascript-api/k6-experimental/websockets/websocket/websocket-close) | Close the WebSocket connection. | +| [WebSocket.ping()](/javascript-api/k6-experimental/websockets/websocket/websocket-ping) | Send a ping. | +| [WebSocket.send(data)](/javascript-api/k6-experimental/websockets/websocket/websocket-send) | Send string data. | +| [WebSocket.addEventListener(event, handler)](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener) | Add an event listener on the connection for specific event. | + +A WebSocket instance also has the following properties: + + +| Class/Property | Description | +| -------------- | ----------- | +| WebSocket.readyState | The current state of the connection. Could be one of [the four states](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState). | +| WebSocket.url | The URL of the connection as resolved by the constructor. | +| WebSocket.bufferedAmount | The number of bytes of data that have been queued using calls to `send()` but not yet transmitted to the network. | +| WebSocket.binaryType | The [`binaryType`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/binaryType) is by default `"ArrayBuffer"`. Setting it throws an exception, as k6 does not support the Blob type. | +| [WebSocket.onmessage](/javascript-api/k6-experimental/websockets/websocket/websocket-onmessage) | A handler for `message` events. | +| [WebSocket.onerror](/javascript-api/k6-experimental/websockets/websocket/websocket-onerror) | A handler for `error` events. | +| [WebSocket.onopen](/javascript-api/k6-experimental/websockets/websocket/websocket-onopen) | A handler for `open` events. | +| [WebSocket.onclose](/javascript-api/k6-experimental/websockets/websocket/websocket-onclose) | A handler for `close` events. | +| [WebSocket.onping](/javascript-api/k6-experimental/websockets/websocket/websocket-onping) | A handler for `ping` events. | +| [WebSocket.onpong](/javascript-api/k6-experimental/websockets/websocket/websocket-onpong) | A handler for `pong` events. | + + +## Websocket metrics + +k6 takes specific measurements for Websockets. +For the complete list, refer to the [Metrics reference](/using-k6/metrics/reference#websockets). + +## Example + +This example shows: +- How a single VU can run multiple WebSockets connections asynchronously. +- How to use the timeout and interval functions to stop the connections after some period. + + + +```javascript +import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.1.0/index.js'; +import { WebSocket } from 'k6/experimental/websockets'; +import { setTimeout, clearTimeout, setInterval, clearInterval } from 'k6/experimental/timers'; + +const chatRoomName = 'publicRoom'; // choose any chat room name +const sessionDuration = randomIntBetween(5000, 60000); // user session between 5s and 1m + +export default function () { + for (let i = 0; i < 4; i++) { + startWSWorker(i); + } +} + +function startWSWorker(id) { + // create a new websocket connection + const ws = new WebSocket(`wss://test-api.k6.io/ws/crocochat/${chatRoomName}/`); + + ws.addEventListener('open', () => { + // change the user name + ws.send(JSON.stringify({ event: 'SET_NAME', new_name: `Croc ${__VU}:${id}` })); + + // listen for messages/errors and log them into console + ws.addEventListener('message', (e) => { + const msg = JSON.parse(e.data); + if (msg.event === 'CHAT_MSG') { + console.log(`VU ${__VU}:${id} received: ${msg.user} says: ${msg.message}`); + } else if (msg.event === 'ERROR') { + console.error(`VU ${__VU}:${id} received:: ${msg.message}`); + } else { + console.log(`VU ${__VU}:${id} received unhandled message: ${msg.message}`); + } + }); + + // send a message every 2-8 seconds + const intervalId = setInterval(() => { + ws.send(JSON.stringify({ event: 'SAY', message: `I'm saying ${randomString(5)}` })); + }, randomIntBetween(2000, 8000)); // say something every 2-8 seconds + + // after a sessionDuration stop sending messages and leave the room + const timeout1id = setTimeout(function () { + clearInterval(intervalId); + console.log(`VU ${__VU}:${id}: ${sessionDuration}ms passed, leaving the chat`); + ws.send(JSON.stringify({ event: 'LEAVE' })); + }, sessionDuration); + + // after a sessionDuration + 3s close the connection + const timeout2id = setTimeout(function () { + console.log(`Closing the socket forcefully 3s after graceful LEAVE`); + ws.close(); + }, sessionDuration + 3000); + + // when connection is closing, clean up the previously created timers + ws.addEventListener('close', () => { + clearTimeout(timeout1id); + clearTimeout(timeout2id); + console.log(`VU ${__VU}:${id}: disconnected`); + }); + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/10-WebSocket-addEventListener.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/10-WebSocket-addEventListener.md new file mode 100644 index 0000000000..defb3efdc2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/10-WebSocket-addEventListener.md @@ -0,0 +1,62 @@ +--- +title: 'WebSocket.addEventListener(event, handler)' +excerpt: 'Set up handler functions for various events on the WebSocket connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener/ +--- + +Set up handler functions for various events on the WebSocket connection. You can define multiple handlers for the same event. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------- | +| event | string | The event name to define a handler for. | +| handler | function | The function to call when the event happens. | + +| Event name | Description | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| open | Emitted when the connection is established. | +| message | Emitted when a message is received from the server. | +| ping | Emitted when a ping is received from the server. The client will automatically send back a `pong`. | +| pong | Emitted when a pong is received from the server. | +| close | Emitted when the connection is closed by the client [WebSocket.close()](/javascript-api/k6-experimental/websockets/websocket/websocket-close) or when the server sends the `close` event with code status 1000 (normal closure). | +| error | Emitted when an error occurs. | + +### Example + +_A k6 script that demonstrates how to add multiple event listeners for the WebSocket `message` connection event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + console.log('connected'); + ws.send(Date.now().toString()); + }; + + ws.onmessage = () => { + console.log('onmessage event handler!'); + }; + + // Multiple event handlers on the same event + ws.addEventListener('message', () => { + console.log('addEventListener event handler!'); + + ws.close(); + }); +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/10-WebSocket-send-data-.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/10-WebSocket-send-data-.md new file mode 100644 index 0000000000..f77df4e459 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/10-WebSocket-send-data-.md @@ -0,0 +1,42 @@ +--- +title: 'WebSocket.send(data)' +excerpt: 'Send a data string through the connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-send/ +--- + +Send a data string through the connection. +You can use `JSON.stringify` to convert a JSON or JavaScript values to a JSON string. + +| Parameter | Type | Description | +| --------- | ------ | ----------------- | +| data | string / ArrayBuffer | The data to send. | + +### Example + +_A k6 script that demonstrates how to add an event listener for the `open` WebSocket connection event sends a message and closes the connection._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + ws.send('lorem ipsum'); + ws.close(); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/15-WebSocket-close--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/15-WebSocket-close--.md new file mode 100644 index 0000000000..c963a417f2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/15-WebSocket-close--.md @@ -0,0 +1,42 @@ +--- +title: 'WebSocket.close([code])' +excerpt: 'Close the WebSocket connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-close/ +--- + +Close the WebSocket connection. + +| Parameter | Type | Description | +| --------------- | -------- | -------------------------------------------- | +| code (optional) | number | WebSocket status code. (default: 1000) . See [the list of supported](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code) close codes. | + + +### Example + +_A k6 script that initiates a WebSocket connection and closes it using the `onopen` handler._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + ws.close(); + console.log('connection closed'); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/20-WebSocket-ping--.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/20-WebSocket-ping--.md new file mode 100644 index 0000000000..1065cf2057 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/20-WebSocket-ping--.md @@ -0,0 +1,43 @@ +--- +title: 'WebSocket.ping()' +excerpt: 'Send a ping. Ping messages can be used to verify that the remote endpoint is responsive.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-ping/ +--- + +Send a ping. You can use ping messages to verify that the remote endpoint is responsive. + +### Example + +_A k6 script that initiates a WebSocket connection, sends a ping, and closes it using the `onopen` handler. The console should log `connection is alive`, since the recipient should automatically emit the `pong` event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + console.log('WebSocket connection established!'); + ws.ping(); + ws.close(); + }; + + ws.onpong = () => { + // As required by the spec, when the ping is received, the recipient must send back a pong. + console.log('connection is alive'); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onclose.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onclose.md new file mode 100644 index 0000000000..f4ca7911b8 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onclose.md @@ -0,0 +1,43 @@ +--- +title: 'WebSocket.onclose' +excerpt: 'A handler function for WebSocket connection close event.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-onclose/ +--- + +A handler for a WebSocket connection `close` event. +For multiple, simultaneous event handlers, use [`WebSocket.addEventListener()`](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener). + +### Example + +_A k6 script that initiates a WebSocket connection, sends a ping, and closes it using `onopen` handler. +The console should also log `WebSocket connection closed` from the `onclose` handler._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + console.log('WebSocket connection established!'); + ws.close(); + }; + + ws.onclose = () => { + console.log('WebSocket connection closed!'); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onerror.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onerror.md new file mode 100644 index 0000000000..d278607574 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onerror.md @@ -0,0 +1,38 @@ +--- +title: 'WebSocket.onerror' +excerpt: 'A handler function for WebSocket connection error event.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-onerror/ +--- + +A handler for a WebSocket connection `error` event. +For multiple, simultaneous event handlers, use [`WebSocket.addEventListener()`](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener). + +### Example + +_A k6 script that initiates a WebSocket connection and sets up a handler for the `error` event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onerror = (e) => { + console.log(e); + ws.close(); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onmessage.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onmessage.md new file mode 100644 index 0000000000..d83afba587 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onmessage.md @@ -0,0 +1,39 @@ +--- +title: 'WebSocket.onmessage' +excerpt: 'A handler function for message event WebSocket.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-onmessage/ +--- + +A handler for a WebSocket connection `message` event. +For multiple, simultaneous event handlers, use [`WebSocket.addEventListener()`](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener). + +### Example + +_A k6 script that initiates a WebSocket connection and sets up a handler for the `message` event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onmessage = (data) => { + console.log('a message received'); + console.log(data); + ws.close(); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onopen.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onopen.md new file mode 100644 index 0000000000..67a3de2c1a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onopen.md @@ -0,0 +1,38 @@ +--- +title: 'WebSocket.onopen' +excerpt: 'A handler function for WebSocket connection open event.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-onopen/ +--- + +A handler for a WebSocket connection `open` event. +For multiple, simultaneous event handlers, use [`WebSocket.addEventListener()`](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener). + +### Example + +_A k6 script that initiates a WebSocket connection and sets up a handler for the `open` event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + console.log('WebSocket connection established!'); + ws.close(); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onping.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onping.md new file mode 100644 index 0000000000..ce18c89262 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onping.md @@ -0,0 +1,40 @@ +--- +title: 'WebSocket.onping' +excerpt: 'A handler function for WebSocket connection ping event.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-onping/ +--- + +A handler for a WebSocket connection `ping` event. +For multiple, simultaneous event handlers, use [`WebSocket.addEventListener()`](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener). + +### Example + +_A k6 script that initiates a WebSocket connection and sets up a handler for the `ping` event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('wss://test-api.k6.io/ws/crocochat/publicRoom/'); + + ws.onping = () => { + console.log('A ping happened!'); + ws.close(); + }; + + ws.onclose = () => { + console.log('WebSocket connection closed!'); + } + + ws.onopen = () => { + ws.send(JSON.stringify({ 'event': 'SET_NAME', 'new_name': `Croc ${__VU}` })); + } + ws.onerror = (err) => { + console.log(err) + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onpong.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onpong.md new file mode 100644 index 0000000000..eb399cdf15 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10 WebSocket/30-WebSocket-onpong.md @@ -0,0 +1,42 @@ +--- +title: 'WebSocket.onpong' +excerpt: 'A handler function for WebSocket connection pong event.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/websocket-onpong/ +--- + +A handler for a WebSocket connection `pong` event. +For multiple, simultaneous event handlers, use [`WebSocket.addEventListener()`](/javascript-api/k6-experimental/websockets/websocket/websocket-addeventlistener). + +### Example + +_A k6 script that initiates a WebSocket connection and setups a handler for the `pong` event._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onpong = () => { + console.log('A pong happened!'); + ws.close(); + }; + + ws.onopen = () => { + ws.ping(); + } +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10-WebSocket.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10-WebSocket.md new file mode 100644 index 0000000000..f92e06b453 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/10-WebSocket.md @@ -0,0 +1,56 @@ +--- +title: 'WebSocket' +description: 'Create a WebSocket connection, and provides a WebSocket instance to interact with the service.' +excerpt: 'Create a WebSocket connection, and provides a WebSocket instance to interact with the service.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/websocket/ +--- + +Creates a WebSocket instance for connection to a remote host. + +The following events can close the connection: + +- remote host close event. +- [WebSocket.close()](/javascript-api/k6-experimental/websockets/websocket/websocket-close). +- k6 VU interruption based on test configuration or CLI commands. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| url | string | The URL to which to connect (e.g. "ws://localhost:10000"). | +| protocols | array | Not yet implemented, reserved for the future use. | +| params | object | [Params](/javascript-api/k6-experimental/websockets/params/) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| WebSocket | An instance of WebSocket object. | + +### Example + +_A k6 script that initiates a WebSocket connection._ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const ws = new WebSocket('ws://localhost:10000'); + + ws.onopen = () => { + console.log('WebSocket connection established!'); + ws.close(); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/20-Params.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/20-Params.md new file mode 100644 index 0000000000..6a2998e9c2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/05 websockets/20-Params.md @@ -0,0 +1,51 @@ +--- +title: 'Params' +description: 'Used for setting various WebSocket request-specific parameters such as headers, tags, etc.' +excerpt: 'Used for setting various WebSocket request-specific parameters such as headers, tags, etc.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/params/ +--- + +`Params` is an object used by the WebSocket constructor. The `Params` object contains request-specific options, such as headers that should be inserted into the connection initialization request. + +| Name | Type | Description | +| --------------------- | ------ | ----------- | +| `Params.compression` | string | Compression algorithm to be used by the WebSocket connection. The only supported algorithm currently is `deflate`. | +| `Params.jar` | [http.CookieJar](/javascript-api/k6-http/cookiejar/) | The cookie jar that will be used when making the initial HTTP request to establish the WebSocket connection. If empty, the [default VU cookie jar](/javascript-api/k6-http/cookiejar-method) will be used. | +| `Params.headers` | object | Custom HTTP headers in key-value pairs that will be added to the initial HTTP request to establish the WebSocket connection. Keys are header names and values are header values. | +| `Params.tags` | object | [Custom metric tags](/using-k6/tags-and-groups/#user-defined-tags) in key-value pairs where the keys are names of tags and the values are tag values. The WebSocket connection will [generate metrics samples](/javascript-api/k6-ws/socket/#websocket-built-in-metrics) with these tags attached, allowing users to filter the results data or set [thresholds on sub-metrics](/using-k6/thresholds/#thresholds-on-tags). | + +### Example of custom metadata headers and tags + +_A k6 script that makes a WebSocket request with a custom header and tags results data with a specific tag_ + + + +```javascript +import { WebSocket } from 'k6/experimental/websockets'; + +export default function () { + const url = 'ws://localhost:10000'; + const params = { + headers: { 'X-MyHeader': 'k6test' }, + tags: { k6test: 'yes' }, + }; + + const ws = new WebSocket(url, null, params); + + ws.onopen = () => { + console.log('WebSocket connection established!'); + ws.close(); + }; +} +``` + + + +The preceding example uses a WebSocket echo server, which you can run with the following command: + + + +```bash +$ docker run --detach --rm --name ws-echo-server -p 10000:8080 jmalloc/echo-server +``` + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto.md new file mode 100644 index 0000000000..9f7075cd37 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto.md @@ -0,0 +1,91 @@ +--- +title: 'webcrypto' +excerpt: "k6 webcrypto experimental API" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/ +--- + + + +With this experimental module, you can use the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) in your k6 scripts. However, note that this API is not yet fully implemented and some algorithms and features might still be missing. + +The Web Crypto API is a JavaScript API for performing cryptographic operations such as encryption, decryption, digital signature generation and verification, and key generation and management. It provides a standard interface to access cryptographic functionality, which can help ensure that cryptographic operations are performed correctly and securely. + +## API + +The module exports a top-level `crypto` object with the following properties and methods: + +| Interface/Function | Description | +| :----------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [getRandomValues](/javascript-api/k6-experimental/webcrypto/crypto/getrandomvalues) | Fills the passed `TypedArray` with cryptographically sound random values. | +| [randomUUID](/javascript-api/k6-experimental/webcrypto/crypto/randomuuid) | Returns a randomly generated, 36 character long v4 UUID. | +| [subtle](/javascript-api/k6-experimental/webcrypto/subtlecrypto) | The [SubtleCrypto](/javascript-api/k6-experimental/webcrypto/subtlecrypto) interface provides access to common cryptographic primitives, such as hashing, signing, encryption, or decryption. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CBC key with + * have generated. + */ + const iv = crypto.getRandomValues(new Uint8Array(16)); + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + plaintext + ); + + /** + * Decrypt the ciphertext using the same key to verify + * that the resulting plaintext is the same as the original. + */ + const deciphered = await crypto.subtle.decrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + ciphertext, + ); + + console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext)) +} + +function arrayBufferToHex(buffer) { + return [...new Uint8Array(buffer)] + .map((x) => x.toString(16).padStart(2, "0")) + .join(""); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto.md new file mode 100644 index 0000000000..99210fc099 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto.md @@ -0,0 +1,20 @@ +--- +title: 'Crypto' +excerpt: 'Crypto offers basic cryptography features.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/crypto/ +--- + +`Crypto` allows access to a cryptographically strong random number generator and to cryptographic primitives. + +## Properties + +| Name | Type | Description | +| :-------------- | :--------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------- | +| `Crypto.subtle` | [SubtleCrypto](/javascript-api/k6-experimental/webcrypto/subtlecrypto) | The SubtleCrypto interface provides access to common cryptographic primitives, such as hashing, signing, encryption, or decryption. | + +## Methods + +| Name | Type | Description | +| :--- | :--- | :---------- | +| `Crypto.getRandomValues()` | [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) | Returns an array of cryptographically secure random values. | +| `Crypto.randomUUID()` | [ArrayBuffer]() | Returns a randomly generated, 36 character long v4 UUID. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto/01 getRandomValues.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto/01 getRandomValues.md new file mode 100644 index 0000000000..59e8cdc0e6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto/01 getRandomValues.md @@ -0,0 +1,48 @@ +--- +title: 'getRandomValues' +excerpt: 'getRandomValues fills the passed TypedArray with cryptographically sound random values.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/crypto/getrandomvalues/ +--- + +The `getRandomValues()` method fills the passed `TypedArray` with cryptographically sound random values. + +## Usage + +``` +getRandomValues(typedArray) +``` + +## Parameters + +| Name | Type | Description | +| :----------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `typedArray` | `TypedArray` | An integer-based `TypedArray` to fill with random values. Accepted `TypedArray` specific types are: `Int8Array`, `Uint8Array`, `Uint8ClampedArray`, `Int16Array`, `Uint16Array`, `Int32Array`, or `Uint32Array`. | + +## Return Value + +The same array is passed as the `typedArray` parameter with its contents replaced with the newly generated random numbers. The `typedArray` parameter is modified in place, and no copy is made. + +## Throws + +| Type | Description | +| :------------------- | :------------------------------------------------------------------- | +| `QuotaExceededError` | Thrown when `typedArray` is too large and its `byteLength` exceeds 65536. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default function () { + const array = new Uint32Array(10); + crypto.getRandomValues(array); + + for (const num of array) { + console.log(num); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto/02 randomUUID.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto/02 randomUUID.md new file mode 100644 index 0000000000..508c9760cd --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/01 Crypto/02 randomUUID.md @@ -0,0 +1,33 @@ +--- +title: 'randomUUID' +excerpt: 'randomUUID produces a 36-characters long string containing a cryptographically random UUID v4.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/crypto/randomuuid/ +--- + +The `randomUUID` method produces a 36-characters long string that contains a cryptographically random UUID v4. + +## Usage + +``` +randomUUID() +``` + +## Return Value + +A string containing a 36-character cryptographically random UUID v4. + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default function () { + const myUUID = crypto.randomUUID(); + + console.log(myUUID); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto.md new file mode 100644 index 0000000000..0ac89cfd7e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto.md @@ -0,0 +1,90 @@ +--- +title: 'SubtleCrypto' +excerpt: 'SubtleCrypto offers low-level cryptographic functions.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/ +--- + +The `SubtleCrypto` interface provides a set of low-level cryptographic primitives such as encryption, decryption, digital signature generation and verification, and key generation and management. It is useful for using secure and efficient cryptographic operations within k6 scripts. + +## Methods + +| Method | Description | +| :-------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------ | +| [encrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt) | Encrypts the given plaintext data using the specified algorithm and key. | +| [decrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt) | Decrypts the given ciphertext data using the specified algorithm and key. | +| [sign](/javascript-api/k6-experimental/webcrypto/subtlecrypto/sign) | Signs the given data using the specified algorithm and key. | +| [verify](/javascript-api/k6-experimental/webcrypto/subtlecrypto/verify) | Verifies the signature of the given data using the specified algorithm and key. | +| [digest](/javascript-api/k6-experimental/webcrypto/subtlecrypto/digest) | Computes the digest (hash) of the given data using the specified algorithm. | +| [generateKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/generatekey) | Generates a new cryptographic key for use with the specified algorithm. | +| [importKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/importkey) | Imports a raw key material into the Web Crypto API, generating a new key object to use with the specified algorithm. +| [exportKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/exportkey) | Exports the raw key material of the given key object. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CBC key with + * have generated. + */ + const iv = crypto.getRandomValues(new Uint8Array(16)); + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + plaintext + ); + + /** + * Decrypt the ciphertext using the same key to verify + * that the resulting plaintext is the same as the original. + */ + const deciphered = await crypto.subtle.decrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + ciphertext, + ); + + console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext)) +} + +function arrayBufferToHex(buffer) { + return [...new Uint8Array(buffer)] + .map((x) => x.toString(16).padStart(2, "0")) + .join(""); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/01 decrypt.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/01 decrypt.md new file mode 100644 index 0000000000..5ce85def58 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/01 decrypt.md @@ -0,0 +1,102 @@ +--- +title: 'decrypt' +excerpt: 'decrypt decrypts some encrypted data' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt/ +--- + +The `decrypt()` method decrypts some encrypted data. + +## Usage + +``` +decrypt(algorithm, key, data) +``` + +## Parameters + +| Name | Type | Description | +| :---------- | :--------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `algorithm` | [AesCtrParams](/javascript-api/k6-experimental/webcrypto/aesctrparams), [AesCbcParams](/javascript-api/k6-experimental/webcrypto/aescbcparams), or [AesGcmParams](/javascript-api/k6-experimental/webcrypto/aesgcmparams) object | Defines the algorithm to use and any extra-parameters. The values given for the extra parameters must match those used in the corresponding [encrypt] call. | +| `key` | [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) | The [key](/javascript-api/k6-experimental/webcrypto/cryptokey) to use for decryption. | +| `data` | `ArrayBuffer`, `TypedArray`, or `DataView` | The encrypted data to be decrypted (also known as _ciphertext_). | + +## Return Value + +A `Promise` that resolves to a new `ArrayBuffer` containing the decrypted data. + +## Throws + +| Type | Description | +| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `InvalidAccessError` | Raised when the requested operation is not valid with the provided key. For instance when an invalid encryption algorithm is used, or a key not matching the selected algorithm is provided. | +| `OperationError` | Raised when the operation failed for an operation-specific reason. For instance, if the algorithm size is invalid, or errors occurred during the process of decrypting the ciphertext. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CBC key with + * have generated. + */ + const iv = crypto.getRandomValues(new Uint8Array(16)); + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + plaintext + ); + + /** + * Decrypt the ciphertext using the same key to verify + * that the resulting plaintext is the same as the original. + */ + const deciphered = await crypto.subtle.decrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + ciphertext, + ); + + console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext)) +} + +function arrayBufferToHex(buffer) { + return [...new Uint8Array(buffer)] + .map((x) => x.toString(16).padStart(2, "0")) + .join(""); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/02 digest.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/02 digest.md new file mode 100644 index 0000000000..524fd5bcca --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/02 digest.md @@ -0,0 +1,50 @@ +--- +title: 'digest' +excerpt: 'digest decrypts some encrypted data' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/digest/ +--- + +The `digest()` method generates a cryptographically secure [digest](https://developer.mozilla.org/en-US/docs/Glossary/Digest) of the given data. A digest is a short fixed-length value derived from some input data. The `digest()` method is commonly used to compute a checksum of data or to verify the integrity of data. + +## Usage + +``` +digest(algorithm, data) +``` + +## Parameters + +| Name | Type | Description | +| :---------- | :-------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `algorithm` | a `string` or object with a single `name` string property | Names the hash function to use. Supported values are `"SHA-1"`, `"SHA-256"`, `"SHA-384"` and `"SHA-512"`. Note that the SHA-1 hash function is not considered safe for cryptographic use. | +| `data` | `ArrayBuffer`, `TypedArray`, or `DataView` | The data to be digested. | + +## Return Value + +A `Promise` that resolves to a new `ArrayBuffer` containing the digest. + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const digest = await crypto.subtle.digest("SHA-256", stringToArrayBuffer("Hello, world!")); + + console.log(arrayBufferToHex(digest)); +} + +function arrayBufferToHex(buffer) { + return [...new Uint8Array(buffer)] + .map((x) => x.toString(16).padStart(2, "0")) + .join(""); +} + +function stringToArrayBuffer(s) { + return Uint8Array.from(new String(s), (x) => x.charCodeAt(0)); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/03 encrypt.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/03 encrypt.md new file mode 100644 index 0000000000..2ebf1c4796 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/03 encrypt.md @@ -0,0 +1,102 @@ +--- +title: 'encrypt' +excerpt: 'encrypt decrypts some encrypted data' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt/ +--- + +The `encrypt()` method encrypts some data. + +## Usage + +``` +encrypt(algorithm, key, data) +``` + +## Parameters + +| Name | Type | Description | +| :---------- | :--- | :---------- | +| `algorithm` | [AesCtrParams](/javascript-api/k6-experimental/webcrypto/aesctrparams), [AesCbcParams](/javascript-api/k6-experimental/webcrypto/aescbcparams), or [AesGcmParams](/javascript-api/k6-experimental/webcrypto/aesgcmparams) object | Defines the algorithm to use and any extra-parameters. | +| `key` | [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) | The [key](/javascript-api/k6-experimental/webcrypto/cryptokey) to use for encryption. | +| `data` | `ArrayBuffer`, `TypedArray`, or `DataView` | The data to be encrypted (also known as "plaintext"). | + +## Return Value + +A `Promise` that resolves to a new `ArrayBuffer` containing the encrypted data. + +## Throws + +| Type | Description | +| :------------------- | :------------------------------------------------------------------- | +| `InvalidAccessError` | Raised when the requested operation is not valid with the provided key. For instance when an invalid encryption algorithm is used, or a key not matching the selected algorithm is provided. | +| `OperationError` | Raised when the operation failed for an operation-specific reason. For instance, if the algorithm size is invalid, or errors occurred during the process of decrypting the ciphertext. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CBC key with + * have generated. + */ + const iv = crypto.getRandomValues(new Uint8Array(16)); + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + plaintext + ); + + /** + * Decrypt the ciphertext using the same key to verify + * that the resulting plaintext is the same as the original. + */ + const deciphered = await crypto.subtle.decrypt( + { + name: "AES-CBC", + iv: iv, + }, + key, + ciphertext, + ); + + console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext)) +} + +function arrayBufferToHex(buffer) { + return [...new Uint8Array(buffer)] + .map((x) => x.toString(16).padStart(2, "0")) + .join(""); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/04 exportKey.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/04 exportKey.md new file mode 100644 index 0000000000..e95f657d8c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/04 exportKey.md @@ -0,0 +1,78 @@ +--- +title: 'exportKey' +excerpt: 'exportKey exports a key in an external, portable format.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/exportkey/ +--- + +The `exportKey()` method takes a [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) object as input and exports it in an external, portable format. + +Note that for a key to be exportable, it must have been created with the `extractable` flag set to `true`. + +## Usage + +``` +exportKey(format, key) +``` + +## Parameters + +| Name | Type | Description | +| :---------- | :--- | :---------- | +| `format` | `string` | Defines the data format the key should be exported in. Currently supported formats: `raw`. | +| `key` | [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) | The [key](/javascript-api/k6-experimental/webcrypto/cryptokey) to export. | + +## Return Value + +A `Promise` that resolves to a new `ArrayBuffer` containing the key. + +## Throws + +| Type | Description | +| :------------------- | :-------------------------------------------------- | +| `InvalidAccessError` | Raised when trying to export a non-extractable key. | +| `NotSupportedError` | Raised when trying to export in an unknown format. | +| `TypeError` | Raised when trying to use an invalid format. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const generatedKey = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: "256" + }, + true, + [ + "encrypt", + "decrypt", + ] + ); + + /** + * Export the key in raw format. + */ + const exportedKey = await crypto.subtle.exportKey("raw", generatedKey); + + /** + * Reimport the key in raw format to verfiy its integrity. + */ + const importedKey = await crypto.subtle.importKey( + "raw", + exportedKey, + "AES-CBC", + true, ["encrypt", "decrypt"] + ); + + console.log(JSON.stringify(importedKey)) +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/05 generateKey.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/05 generateKey.md new file mode 100644 index 0000000000..f949440cc2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/05 generateKey.md @@ -0,0 +1,57 @@ +--- +title: 'generateKey' +excerpt: 'generateKey generates a new key.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/generatekey/ +--- + +The `generateKey()` generates a new cryptographic key and returns it as a [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) object that can be used with the Web Crypto API. + +## Usage + +``` +generateKey(algorithm, extractable, keyUsages) +``` + +## Parameters + +| Name | Type | Description | +| :------------ | :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `algorithm` | `string`, [AesKeyGenParams](/javascript-api/k6-experimental/webcrypto/aeskeygenparams) or [HmacKeyGenParams](/javascript-api/k6-experimental/webcrypto/hmackeygenparams) | The type of key to generate. Can be either a string with any of the currently supported algorithms: `AES-CBC`, `AES-GCM`, `AES-CTR`, and `HMAC` as value, or any of the [AesKeyGenParams](/javascript-api/k6-experimental/webcrypto/aeskeygenparams) or [HmacKeyGenParams](/javascript-api/k6-experimental/webcrypto/hmackeygenparams) objects. | +| `extractable` | `boolean` | Whether the key can be exported using [exportKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/exportkey). | +| `keyUsages` | `Array` | An array of strings describing what operations can be performed with the key. Currently supported usages include `encrypt`, `decrypt`, `sign`, and `verify`. | + +## Return Value + +A `Promise` that resolves with the generated key as a [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) object. + +## Throws + +| Type | Description | +| :------------ | :------------------------------------------------------------------------------------------- | +| `SyntaxError` | Raised when the `keyUsages` parameter is empty but the key is of type `secret` or `private`. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256 + }, + true, + [ + "encrypt", + "decrypt", + ] + ); + + console.log(JSON.stringify(key)) +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/06 importKey.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/06 importKey.md new file mode 100644 index 0000000000..fdae2bc703 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/06 importKey.md @@ -0,0 +1,78 @@ +--- +title: 'importKey' +excerpt: 'importKey imports a key from an external, portable format and gives you a CryptoKey object.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/importkey/ +--- + +The `importKey()` imports a key from an external, portable format, and gives you a [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) object that can be used with the Web Crypto API. + +## Usage + +``` +importKey(format, keyData, algorithm, extractable, keyUsages) +``` + +## Parameters + +| Name | Type | Description | +| :------------ | :-------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `format` | `string` | Defines the data format of the key to import. Currently supported formats: `raw`. | +| `keyData` | `ArrayBuffer`, `TypedArray` or `DataView` | the data to import the key from. | +| `algorithm` | a `string` or object with a single `name` string property | The algorithm to use to import the key. Currently supported algorithms: `AES-CBC`, `AES-GCM`, `AES-CTR`, and `HMAC`. | +| `extractable` | `boolean` | Indicates whether it will be possible to export the key using [exportKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/exportkey). | +| `keyUsages` | `Array` | An array of strings describing what operations can be performed with the key. Currently supported usages include `encrypt`, `decrypt`, `sign`, and `verify`. | + +## Return Value + +A `Promise` that resolves with the imported key as a [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) object. + +## Throws + +| Type | Description | +| :------------ | :---------------------------------------------------------------------------------------------- | +| `SyntaxError` | Raised when the `keyUsages` parameter is empty but the key is of type `secret` or `private`. | +| `TypeError` | Raised when trying to use an invalid format, or if the `keyData` is not suited for that format. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const generatedKey = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: "256" + }, + true, + [ + "encrypt", + "decrypt", + ] + ); + + /** + * Export the key in raw format. + */ + const exportedKey = await crypto.subtle.exportKey("raw", generatedKey); + + /** + * Reimport the key in raw format to verfiy its integrity. + */ + const importedKey = await crypto.subtle.importKey( + "raw", + exportedKey, + "AES-CBC", + true, ["encrypt", "decrypt"] + ); + + console.log(JSON.stringify(importedKey)) +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/07 sign.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/07 sign.md new file mode 100644 index 0000000000..c0ffa515d6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/07 sign.md @@ -0,0 +1,79 @@ +--- +title: 'sign' +excerpt: 'sign generates a digital signature.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/sign/ +--- + +The `sign()` operation generates a digital signature of the provided `data`, using the given [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) object. + +## Usage + +``` +sign(algorithm, key, data) +``` + +## Parameters + +| Name | Type | Description | +| :---------- | :--------------------------------------------------------------- | :----------------------------------------------------------- | +| `algorithm` | `string` or object with a single `name` string property | The signature algorithm to use. Currently supported: `HMAC`. | +| `key` | [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) | The key to use for signing. | +| `data` | `ArrayBuffer`, `TypedArray`, or `DataView` | The data to be signed. | + +## Return Value + +A `Promise` that resolves with the signature as an `ArrayBuffer`. + +## Throws + +| Type | Description | +| :------------------- | :--------------------------------------------------------------------------------------------------------------------- | +| `InvalidAccessError` | Raised when the signing key either does not support signing operation, or is incompatible with the selected algorithm. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const generatedKey = await crypto.subtle.generateKey( + { + name: "HMAC", + hash: { name: "SHA-1" }, + }, + true, + [ + "sign", + "verify", + ] + ); + + const data = string2ArrayBuffer("Hello World"); + + /** + * Signes the encoded data with the provided key using the HMAC algorithm + * the returned signature can be verified using the verify method. + */ + const signature = await crypto.subtle.sign("HMAC", generatedKey, data); + + /** + * Verifies the signature of the encoded data with the provided key using the HMAC algorithm. + */ + const verified = await crypto.subtle.verify("HMAC", generatedKey, signature, data); + + console.log("verified: ", verified) +} + +function string2ArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/08 verify.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/08 verify.md new file mode 100644 index 0000000000..720d81c9e0 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/02 SubtleCrypto/08 verify.md @@ -0,0 +1,80 @@ +--- +title: 'verify' +excerpt: 'verify verifies a digital signature.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/subtlecrypto/verify/ +--- + +The `verify()` operation verifies a digital signature. It ensures that some data was signed by a known key and that the data has not been tampered with since it was signed. + +## Usage + +``` +verify(algorithm, key, signature, data) +``` + +## Parameters + +| Name | Type | Description | +| :---------- | :--------------------------------------------------------------- | :------------------------------------------------- | +| `algorithm` | `string` or object with a single `name` string property | The algorithm to use. Currently supported: `HMAC`. | +| `key` | [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) | The key that will be used to verify the signature. | +| `signature` | `ArrayBuffer` | The signature to verify. | +| `data` | `ArrayBuffer` | The data whose signature is to be verified. | + +## Return Value + +A `Promise` that resolves to a `boolean` value indicating if the signature is valid. + +## Throws + +| Type | Description | +| :------------------- | :-------------------------------------------------- | +| `InvalidAccessError` | Raised when the key either does not support the `verify` operation, or is incompatible with the selected algorithm. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const generatedKey = await crypto.subtle.generateKey( + { + name: "HMAC", + hash: { name: "SHA-1" }, + }, + true, + [ + "sign", + "verify", + ] + ); + + const data = string2ArrayBuffer("Hello World"); + + /** + * Signes the encoded data with the provided key using the HMAC algorithm + * the returned signature can be verified using the verify method. + */ + const signature = await crypto.subtle.sign("HMAC", generatedKey, data); + + /** + * Verifies the signature of the encoded data with the provided key using the HMAC algorithm. + */ + const verified = await crypto.subtle.verify("HMAC", generatedKey, signature, data); + + console.log("verified: ", verified) +} + +function string2ArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/03 CryptoKey.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/03 CryptoKey.md new file mode 100644 index 0000000000..4e43bdc761 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/03 CryptoKey.md @@ -0,0 +1,16 @@ +--- +title: 'CryptoKey' +excerpt: 'CryptoKey represents a cryptographic key used for encryption, decryption, signing, or verification.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/cryptokey/ +--- + +The `CryptoKey` object represents a cryptographic key used for [encryption](/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt), [decryption](/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt), [signing](/javascript-api/k6-experimental/webcrypto/subtlecrypto/sign), or [verification](/javascript-api/k6-experimental/webcrypto/subtlecrypto/verify) within the webcrypto module. The `CryptoKey` object is created using the SubtleCrypto.generateKey() or SubtleCrypto.importKey() methods. + +## Properties + +| Property | Type | Description | +| :---------- | :--------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| type | `string` | Indicates the type of the key material. Possible values are `public`, `private`, `secret`, `unspecified`, or `unknown`. | +| extractable | `boolean` | Indicates whether the raw key material can be exported. | +| algorithm | `object` | An object containing the algorithm used to generate or import the key. | +| usages | `string[]` | An array of strings indicating the cryptographic operations that the key can be used for. Possible values are `encrypt`, `decrypt`, `sign`, `verify`, `deriveKey`, `deriveBits`, `wrapKey`, and `unwrapKey`. | diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/04 AesKeyGenParams.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/04 AesKeyGenParams.md new file mode 100644 index 0000000000..e36e036433 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/04 AesKeyGenParams.md @@ -0,0 +1,38 @@ +--- +title: 'AesKeyGenParams' +excerpt: 'AesKeyGenParams represents the object that should be passed as the algorithm parameter into the generateKey operation, when generating an AES key.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/aeskeygenparams/ +--- + +The `AesKeyGenParams` object represents the object that should be passed as the algorithm parameter into the [generateKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/generatekey) operation when generating an AES key. + +## Properties + +| Property | Type | Description | +| :------- | :------- | :--------------------------------------------------------------------------------- | +| name | `string` | The name of the algorithm. Possible values are `AES-CBC`, `AES-CTR`, and `AES-GCM`.| +| length | `number` | The length of the key in bits. Possible values are 128, 192 or 256. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256 + }, + true, + [ + "encrypt", + "decrypt", + ] + ); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/05 HmacKeyGenParams.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/05 HmacKeyGenParams.md new file mode 100644 index 0000000000..e615d000db --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/05 HmacKeyGenParams.md @@ -0,0 +1,40 @@ +--- +title: 'HmacKeyGenParams' +excerpt: 'HmacKeyGenParams represents the object that should be passed as the algorithm parameter into the generateKey operation, when generating an HMAC key.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/hmackeygenparams/ +--- + +The `HmacKeyGenParams` object represents the object that should be passed as the algorithm parameter into the [generateKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/generatekey) operation when generating an HMAC key. + +## Properties + +| Property | Type | Description | +| :---------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| name | `string` | The should be set to `HMAC`. | +| hash | `string` | The name of the digest function to use. Possible values are `SHA-1`, `SHA-256`, `SHA-384` and `SHA-512`. | +| length (optional) | `number` | The length of the key in bits. If this is omitted, the length of the key is equal to the block size of the hash function you have chosen. We recommend to leave this parameter empty, unless you have a good reason to use something different. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const key = await crypto.subtle.generateKey( + { + name: "HMAC", + hash: { name: "SHA-512" }, + length: 256, + }, + true, + [ + "sign", + "verify", + ] + ); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/06 AesCtrParams.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/06 AesCtrParams.md new file mode 100644 index 0000000000..85582b1ff9 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/06 AesCtrParams.md @@ -0,0 +1,66 @@ +--- +title: 'AesCtrParams' +excerpt: 'AesCtrParams represents the object that should be passed as the algorithm parameter into the encrypt and decrypt operation when using the AES-CTR algorithm.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/aesctrparams/ +--- + +The `AesCtrParams` object represents the object that should be passed as the algorithm parameter into the [encrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt) and [decrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt) operation when using the AES-CTR algorithm. + +For more details, head to the MDN Web Crypto API documentation on [AES-CTR](https://developer.mozilla.org/en-US/docs/Web/API/AesCtrParams). + +## Properties + +| Property | Type | Description | +| :------- | :----------------------------------------- | :------------------------------------------------------------------ | +| name | `string` | Should be set to `AES-CTR`. | +| counter | `ArrayBuffer`, `TypedArray`, or `DataView` | The initial value of the counter block. This must be 16-bytes long, like the AES block size. | +| length | `number` | The number of bits in the counter block that are used for the actual counter. It is recommended to use 64 (half of the counter block). | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CTR algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-CTR", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CTR key with + * have generated. + */ + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-CTR", + counter: crypto.getRandomValues(new Uint8Array(16)), + length: 128, + }, + key, + plaintext + ); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/07 AesCbcParams.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/07 AesCbcParams.md new file mode 100644 index 0000000000..6032a7f7eb --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/07 AesCbcParams.md @@ -0,0 +1,64 @@ +--- +title: 'AesCbcParams' +excerpt: 'AesCbcParams represents the object that should be passed as the algorithm parameter into the encrypt and decrypt operation when using the AES-CBC algorithm.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/aescbcparams/ +--- + +The `AesCbcParams` object represents the object that should be passed as the algorithm parameter into the [encrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt) and [decrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt) operation when using the AES-CBC algorithm. + +For more details, head to the [MDN Web Crypto API documentation on AES-CBC](https://developer.mozilla.org/en-US/docs/Web/API/AesCbcParams). + +## Properties + +| Property | Type | Description | +| :------- | :----------------------------------------- | :------------------------------------------------------------------ | +| name | `string` | Should be set to `AES-CBC`. | +| iv | `ArrayBuffer`, `TypedArray`, or `DataView` | The initialization vector. Must be 16 bytes, unpredictable and cryptographically random. Yet, it doesn't need to be secret and can be transmitted along with the ciphertext. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-CBC", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CBC key with + * have generated. + */ + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-CBC", + iv: crypto.getRandomValues(new Uint8Array(16)), + }, + key, + plaintext + ); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/08 AesGcmParams.md b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/08 AesGcmParams.md new file mode 100644 index 0000000000..31cc86aecb --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/07 k6-experimental/06 webcrypto/08 AesGcmParams.md @@ -0,0 +1,66 @@ +--- +title: 'AesGcmParams' +excerpt: 'AesGcmParams represents the object that should be passed as the algorithm parameter into the encrypt and decrypt operation when using the AES-GCM algorithm.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/aesgcmparams/ +--- + +The `AesGcmParams` object represents the object that should be passed as the algorithm parameter into the [encrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt) and [decrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt) operation when using the AES-GCM algorithm. + +For more details, head to the [MDN Web Crypto API documentation on AES-GCM](https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams). + +## Properties + +| Property | Type | Description | +| :------------------------ | :----------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| name | `string` | Should be set to `AES-GCM`. | +| iv | `ArrayBuffer`, `TypedArray`, or `DataView` | The initialization vector. It must be 12 bytes long, unpredictable and cryptographically random. It must be unique for every encryption operation carried out with a given key. Never reuse an iv with the same key. Yet, it doesn't need to be secret and can be transmitted along with the ciphertext. | +| additionalData (optional) | `ArrayBuffer`, `TypedArray` or `DataView` | Additional data that should be authenticated, but not encrypted. It must be included in the calculation of the authentication tag, but not encrypted itself. | +| tagLength (optional) | `number` | The length of the authentication tag in bits. Should be set, and will default to 96. | + +## Example + + + +```javascript +import { crypto } from "k6/experimental/webcrypto"; + +export default async function () { + const plaintext = stringToArrayBuffer("Hello, World!"); + + /** + * Generate a symmetric key using the AES-CBC algorithm. + */ + const key = await crypto.subtle.generateKey( + { + name: "AES-GCM", + length: 256, + }, + true, + ["encrypt", "decrypt"] + ); + + /** + * Encrypt the plaintext using the AES-CBC key with + * have generated. + */ + const ciphertext = await crypto.subtle.encrypt( + { + name: "AES-GCM", + iv: crypto.getRandomValues(new Uint8Array(12)), + }, + key, + plaintext + ); +} + +function stringToArrayBuffer(str) { + const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char + const bufView = new Uint16Array(buf); + for (let i = 0, strLen = str.length; i < strLen; i++) { + bufView[i] = str.charCodeAt(i); + } + return buf; +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html.md b/src/data/markdown/docs/02 javascript api/08 k6-html.md index f1f116eb5f..5af000a75b 100644 --- a/src/data/markdown/docs/02 javascript api/08 k6-html.md +++ b/src/data/markdown/docs/02 javascript api/08 k6-html.md @@ -2,6 +2,14 @@ title: "k6/html" excerpt: 'The k6/html module contains functionality for HTML parsing.' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-html/ --- The k6/html module contains functionality for HTML parsing. + +| Function | Description | +| -------- | ----------- | +| [parseHTML(src)](/javascript-api/k6-html/parsehtml) | Parse an HTML string and populate a [Selection](/javascript-api/k6-html/selection) object. | + +| Class | Description | +| -------- | ----------- | +| [Element](/javascript-api/k6-html/element) | An HTML DOM element as returned by the [Selection](/javascript-api/k6-html/selection) API. | +| [Selection](/javascript-api/k6-html/selection) | A jQuery-like API for accessing HTML DOM elements. | diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/10-parseHTML- src -.md b/src/data/markdown/docs/02 javascript api/08 k6-html/10-parseHTML- src -.md new file mode 100644 index 0000000000..a743e37ecd --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/10-parseHTML- src -.md @@ -0,0 +1,36 @@ +--- +title: 'parseHTML( src )' +description: 'Parse an HTML string and populate a Selection object.' +excerpt: 'Parse an HTML string and populate a Selection object.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/parsehtml/ +--- + +Parse an HTML string and populate a [Selection](/javascript-api/k6-html/selection) object. + +| Parameter | Type | Description | +| --------- | ------ | ------------ | +| src | string | HTML source. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------------- | +| [Selection](/javascript-api/k6-html/selection) | A Selection object. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import http from 'k6/http'; + +export default function () { + const res = http.get('https://k6.io'); + const doc = parseHTML(res.body); // equivalent to res.html() + const pageTitle = doc.find('head title').text(); + const langAttr = doc.find('html').attr('lang'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/20-Element -k6-html-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/20-Element -k6-html-.md new file mode 100644 index 0000000000..419e1448d0 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/20-Element -k6-html-.md @@ -0,0 +1,161 @@ +--- +title: 'Element' +description: 'An HTML DOM element as returned by the Selection API.' +excerpt: 'An HTML DOM element as returned by the Selection API.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/element/ +--- + +Represents a DOM element matched by a [Selection](/javascript-api/k6-html/selection), +and provides an API to inspect the element content. + +Use [Selection.get(index)](/javascript-api/k6-html/selection/selection-get) to return an Element object. + +The Element object provides a similar API to the [DOM Element API](https://developer.mozilla.org/en-US/Web/API/Element) to retrieve element information. + +| Method | Description | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| nodeName | The name of the element. | +| nodeType | The type of the element. | +| nodeValue | The element value. | +| id | The id of the element. | +| innerHTML | Is a DOMString representing the markup of the element's content. | +| textContent | The element content. | +| ownerDocument | [Element](/javascript-api/k6-html/element) | +| attributes | An array of attributes. | +| firstChild | [Element](/javascript-api/k6-html/element) | +| lastChild | [Element](/javascript-api/k6-html/element) | +| childElementCount | The number of children elements. | +| firstElementChild | [Element](/javascript-api/k6-html/element) | +| lastElementChild | [Element](/javascript-api/k6-html/element) | +| previousSibling | [Element](/javascript-api/k6-html/element) | +| nextSibling | [Element](/javascript-api/k6-html/element) | +| previousElementSibling | [Element](/javascript-api/k6-html/element) | +| nextElementSibling | [Element](/javascript-api/k6-html/element) | +| parentElement | [Element](/javascript-api/k6-html/element) | +| parentNode | [Element](/javascript-api/k6-html/element) | +| childNodes | Array of [Element](/javascript-api/k6-html/element) | +| children | Array of [Element](/javascript-api/k6-html/element) | +| classList | An array of class names. | +| className | The class name string | +| lang | The value of the lang attribute. | +| toString | The element string representation. | +| hasAttribute | Boolean | +| getAttribute | getAttributeNode | +| hasAttributes | Boolean | +| hasChildNodes | Boolean | +| isSameNode | Boolean | +| isEqualNode | Boolean | +| getElementsByClassName | Return an array of [Element](/javascript-api/k6-html/element). | +| getElementsByTagName | Return an array of [Element](/javascript-api/k6-html/element). | +| querySelector | Returns the first [Element](/javascript-api/k6-html/element) which matches the specified selector string relative to the element | +| querySelectorAll | Returns all the [Element](/javascript-api/k6-html/element) which matches the specified selector string relative to the element | +| contains | | +| matches | Returns a Boolean indicating whether or not the element would be selected by the specified selector string | +| namespaceURI | The namespace URI of the element. | +| isDefaultNamespace | Returns a Boolean indicating whether the element has the default namespace. | + +Additionally, Element can provide more methods depending on the Element type. + +- **AnchorElement**: hash, host, hostname, port, username, password, origin, pathname, protocol, relist, search, text. + +- **ButtonElement**: form, formAction, formEnctype, formMethod, formNoValidate, formTarget, labels, name, value. + +- **CanvasElement**: width, height + +- **DataListElement**: options + +- **FieldSetElement**: elements, type, form + +- **FormElement**: elements, length, method + +- **InputElement**: form + +- **LabelElement**: control, form + +- **LegendElement**: form + +- **LinkElement**: relList + +- **MapElement**: areas, images + +- **ObjectElement**: form + +- **OptionElement**: disabled, form, index, label, text, value + +- **OutputElement**: value, labels + +- **ProgressElement**: max, value, position + +- **ScriptElement**: text + +- **SelectElement**: form, length, options, selectedOptions, selectedIndex, value + +- **StyleElement**: text + +- **TableElement**: caption, thead, tbody, tfoot, rows + +- **TableCellElement**: cellIndex, colSpan, rowSpan, headers + +- **TableRowElement**: cells, colSpan, sectionRowIndex, rowIndex + +- **VideoElement**: textTracks + +- **TitleElement**: text + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
Value term 1
+
Value term 2
+
+ `; + const sel = parseHTML(content).find('dl').children(); + + const el1 = sel.get(0); + const el2 = sel.get(1); + + console.log(el1.nodeName()); + console.log(el1.id()); + console.log(el1.textContent()); + + console.log(el2.nodeName()); + console.log(el2.id()); + console.log(el2.textContent()); + + sleep(1); +} +``` + +
+ + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +\t6 + `; + const el = parseHTML(content).find('a').get(0); + + console.log(el.nodeName()); + console.log(el.innerHTML()); + console.log(el.host()); + console.log(el.hostname()); + console.log(el.protocol()); + + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection.md new file mode 100644 index 0000000000..aba758aef2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection.md @@ -0,0 +1,70 @@ +--- +title: 'Selection' +description: 'A jQuery-like API for accessing HTML DOM elements.' +excerpt: 'A jQuery-like API for accessing HTML DOM elements.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/ +--- + +Represents a set of nodes in a DOM tree. + +Selections have a jQuery-compatible API, but with two caveats: + +- CSS and screen layout are not processed, thus calls like css() and offset() are unavailable. +- DOM trees are read-only, you can't set attributes or otherwise modify nodes. + +(Note that the read-only nature of the DOM trees is purely to avoid a maintenance burden on code with seemingly no practical use - if a compelling use case is presented, modification can easily be implemented.) + +| Method | Description | +| ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [Selection.attr(name)](/javascript-api/k6-html/selection/selection-attr) | Get the value of an attribute for the first element in the Selection. | +| [Selection.children([selector])](/javascript-api/k6-html/selection/selection-children) | Get the children of each element in the set of matched elements, optionally filtered by a selector. | +| [Selection.closest(selector)](/javascript-api/k6-html/selection/selection-closest) | Get the first element that matches the selector by testing the element itself and traversing up through its ancestors | +| [Selection.contents()](/javascript-api/k6-html/selection/selection-contents) | Get the children of each element in the set of matched elements, including text and comment nodes. | +| [Selection.data([key])](/javascript-api/k6-html/selection/selection-data) | Return the value at the named data store for the first element in the set of matched elements. | +| [Selection.each(fn)](/javascript-api/k6-html/selection/selection-each) | Iterate and execute a function for each matched element. | +| [Selection.eq(index)](/javascript-api/k6-html/selection/selection-eq) | Reduce the set of matched elements to the one at the specified index. | +| [Selection.filter(selector)](/javascript-api/k6-html/selection/selection-filter) | Reduce the set of matched elements to those that match the selector or pass the function's test. | +| [Selection.find(selector)](/javascript-api/k6-html/selection/selection-find) | Find the selection descendants, filtered by a selector. | +| [Selection.first()](/javascript-api/k6-html/selection/selection-first) | Reduce the set of matched elements to the first in the set. | +| [Selection.get(index)](/javascript-api/k6-html/selection/selection-get) | Retrieve the [Element (k6/html)](/javascript-api/k6-html/element) matched by the selector | +| [Selection.has(selector)](/javascript-api/k6-html/selection/selection-has) | Reduce the set of matched elements to those that have a descendant that matches the selector | +| [Selection.html()](/javascript-api/k6-html/selection/selection-html) | Get the HTML contents of the first element in the set of matched elements | +| [Selection.is(selector)](/javascript-api/k6-html/selection/selection-is) | Check the current matched set of elements against a selector or element and return true if at least one of these elements matches the given arguments. | +| [Selection.last()](/javascript-api/k6-html/selection/selection-last) | Reduce the set of matched elements to the final one in the set. | +| [Selection.map(fn)](/javascript-api/k6-html/selection/selection-map) | Pass each selection in the current matched set through a function, producing a new Array containing the return values. | +| [Selection.nextAll([selector])](/javascript-api/k6-html/selection/selection-nextall) | Get all following siblings of each element in the set of matched elements, optionally filtered by a selector. | +| [Selection.next([selector])](/javascript-api/k6-html/selection/selection-next) | Get the immediately following sibling of each element in the set of matched element | +| [Selection.nextUntil([selector], [filter])](/javascript-api/k6-html/selection/selection-nextuntil) | Get all following siblings of each element up to but not including the element matched by the selector. | +| [Selection.not(selector)](/javascript-api/k6-html/selection/selection-not) | Remove elements from the set of matched elements | +| [Selection.parent([selector])](/javascript-api/k6-html/selection/selection-parent) | Get the parent of each element in the current set of matched elements, optionally filtered by a selector. | +| [Selection.parents([selector])](/javascript-api/k6-html/selection/selection-parents) | Get the ancestors of each element in the current set of matched elements, optionally filtered by a selector. | +| [Selection.parentsUntil([selector], [filter])](/javascript-api/k6-html/selection/selection-parentsuntil) | Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector. | +| [Selection.prevAll([selector])](/javascript-api/k6-html/selection/selection-prevall) | Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector. | +| [Selection.prev([selector])](/javascript-api/k6-html/selection/selection-prev) | Get the immediately preceding sibling of each element in the set of matched elements. | +| [Selection.prevUntil([selector], [filter])](/javascript-api/k6-html/selection/selection-prevuntil) | Get all preceding siblings of each element up to but not including the element matched by the selector. | +| [Selection.size()](/javascript-api/k6-html/selection/selection-size) | Return the number of elements in the Selection. | +| [Selection.serialize()](/javascript-api/k6-html/selection/selection-size) | Encode a set of form elements as a string in standard URL-encoded notation for submission. | +| [Selection.serializeArray()](/javascript-api/k6-html/selection/selection-size) | Encode a set of form elements as an array of names and values. | +| [Selection.serializeObject()](/javascript-api/k6-html/selection/selection-serializeobject) | Encode a set of form elements as an object. | +| [Selection.slice(start [, end])](/javascript-api/k6-html/selection/selection-slice) | Reduce the set of matched elements to a subset specified by a range of indices. | +| [Selection.text()](/javascript-api/k6-html/selection/selection-text) | Get the text content of the selection. | +| [Selection.toArray()](/javascript-api/k6-html/selection/selection-toarray) | Retrieve all the elements contained in the Selection, as an array. | +| [Selection.val()](/javascript-api/k6-html/selection/selection-val) | Get the current value of the first element in the set of matched elements. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import http from 'k6/http'; + +export default function () { + const res = http.get('https://k6.io'); + const doc = parseHTML(res.body); + const pageTitle = doc.find('head title').text(); + const langAttr = doc.find('html').attr('lang'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-attr-name-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-attr-name-.md new file mode 100644 index 0000000000..dd89fa86b6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-attr-name-.md @@ -0,0 +1,35 @@ +--- +title: 'Selection.attr(name)' +excerpt: 'Get the value of an attribute for the first element in the Selection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-attr/ +--- + +Get the value of an attribute for the first element in the Selection. +Mimics [jquery.attr](https://api.jquery.com/attr/) + +| Parameter | Type | Description | +| --------- | ------ | -------------------------------- | +| name | string | The name of the attribute to get | + +### Returns + +| Type | Description | +| ------ | -------------------------- | +| string | The value of the attribute | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import http from 'k6/http'; + +export default function () { + const res = http.get('https://k6.io'); + const doc = parseHTML(res.body); + const langAttr = doc.find('html').attr('lang'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-children--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-children--selector--.md new file mode 100644 index 0000000000..3f9b80a180 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-children--selector--.md @@ -0,0 +1,57 @@ +--- +title: 'Selection.children([selector])' +excerpt: 'Get the children of each element in the set of matched elements, optionally filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-children/ +--- + +Get the children of each element in the set of matched elements, optionally filtered by a selector. +Mimics [jquery.children](https://api.jquery.com/children/) + +| Parameter | Type | Description | +| ------------------- | ------ | -------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ----------------------- | +| [Selection](/javascript-api/k6-html/selection) | The children Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + const sel = doc.find('dl'); + + console.log(sel.children().size()); + console.log(sel.children('dt').size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-closest-selector-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-closest-selector-.md new file mode 100644 index 0000000000..95d6b5dd70 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-closest-selector-.md @@ -0,0 +1,56 @@ +--- +title: 'Selection.closest(selector)' +excerpt: 'For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-closest/ +--- + +For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. +Mimics [jquery.closest](https://api.jquery.com/closest/) + +| Parameter | Type | Description | +| --------- | ------ | ------------------------------------------------------------------- | +| selector | string | A string containing a selector expression to match elements against | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ----------- | +| [Selection](/javascript-api/k6-html/selection) | Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • I
  • +
  • II +
      +
    • A
    • +
    • B +
        +
      • 1
      • +
      • 2
      • +
      • 3
      • +
      +
    • +
    • C
    • +
    +
  • +
  • III
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li.item-a').closest('ul'); + console.log(sel.attr('class')); + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-contents--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-contents--.md new file mode 100644 index 0000000000..71921ea312 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-contents--.md @@ -0,0 +1,53 @@ +--- +title: 'Selection.contents()' +excerpt: 'Get the children of each element in the set of matched elements, including text and comment nodes.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-contents/ +--- + +Get the children of each element in the set of matched elements, including text and comment nodes. +Mimics [jquery.contents](https://api.jquery.com/contents/). + +### Returns + +| Type | Description | +| ---------------------------------------------- | ----------- | +| [Selection](/javascript-api/k6-html/selection) | Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dt'); + + console.log(sel.contents().text()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-data--key--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-data--key--.md new file mode 100644 index 0000000000..f39abbdf43 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-data--key--.md @@ -0,0 +1,44 @@ +--- +title: 'Selection.data([key])' +excerpt: 'Return the value at the named data store for the first element in the set of matched elements.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-data/ +--- + +Return the value at the named data store for the first element in the set of matched elements. +Mimics [jquery.data](https://api.jquery.com/data/) + +| Parameter | Type | Description | +| -------------- | ------ | ----------------------------------------- | +| key (optional) | string | A string naming the piece of data to set. | + +### Returns + +| Type | Description | +| ------ | ---------------------------------- | +| string | The value at the named data store. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +

Hola

+ `; + + const doc = parseHTML(content); + const sel = doc.find('h1'); + + console.log(sel.data().testID); + console.log(sel.data('test-id')); + console.log(sel.data('testId')); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-each-fn-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-each-fn-.md new file mode 100644 index 0000000000..b2878c1d52 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-each-fn-.md @@ -0,0 +1,51 @@ +--- +title: 'Selection.each(fn)' +excerpt: 'Iterate over a Selection, executing a function for each matched element.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-each/ +--- + +Iterate over a [Selection](/javascript-api/k6-html/selection), executing a function for each matched element. +Mimics [jquery.each](https://api.jquery.com/each/) + +| Parameter | Type | Description | +| --------- | -------- | --------------------------------------------------------- | +| fn | function | A function to iterate all the Elements of the Collection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + doc.find('dl').each(function (idx, el) { + console.log(el.innerHTML()); + }); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-eq-index-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-eq-index-.md new file mode 100644 index 0000000000..b85d6502b7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-eq-index-.md @@ -0,0 +1,59 @@ +--- +title: 'Selection.eq(index)' +excerpt: 'Reduce the set of matched elements to the one at the specified index.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-eq/ +--- + +Reduce the set of matched elements to the one at the specified index. +Mimics [jquery.eq](https://api.jquery.com/eq/). + +| Parameter | Type | Description | +| --------- | ------ | ---------------------------------------------------------- | +| index | Number | An integer indicating the 0-based position of the element. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dt'); + + console.log(sel.eq(0).html()); + console.log(sel.eq(1).html()); + console.log(sel.eq(2).html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-filter-selector-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-filter-selector-.md new file mode 100644 index 0000000000..d82a55cde7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-filter-selector-.md @@ -0,0 +1,68 @@ +--- +title: 'Selection.filter(selector)' +excerpt: 'Reduce the set of matched elements to those that match the selector or pass the function test.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-filter/ +--- + +Reduce the set of matched elements to those that match the selector or pass the function's test. +Mimics [jquery.filter](https://api.jquery.com/filter/) + +| Parameter | Type | Description | +| --------- | ---------------------------------------------- | -------------------------------------------------------------------- | +| selector | function | A function used as a test for each element in the set. | +| selector | string | A string containing a selector expression to match elements against. | +| selector | [Selection](/javascript-api/k6-html/selection) | A selection to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | --------------------- | +| [Selection](/javascript-api/k6-html/selection) | The filter selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + let sel; + const els = doc.find('dl').children(); + + sel = els.filter('#term-2'); + console.log(sel.text()); + + sel = els.filter(function (idx, el) { + return el.text() === 'definition 3-a'; + }); + console.log(sel.text()); + + sel = els.filter(doc.find('dl dt#term-1')); + console.log(sel.text()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-find-selector-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-find-selector-.md new file mode 100644 index 0000000000..e3ea104cad --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-find-selector-.md @@ -0,0 +1,37 @@ +--- +title: 'Selection.find(selector)' +excerpt: 'Find the selection descendants, filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-find/ +--- + +Find the selection descendants, filtered by a selector. It returns a [Selection](/javascript-api/k6-html/selection) object. +Mimics [jquery.find](https://api.jquery.com/find/) + +| Parameter | Type | Description | +| --------- | ------ | -------------------------------------------------------------------- | +| selector | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ----------------- | +| [Selection](/javascript-api/k6-html/selection) | Selection object. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import http from 'k6/http'; + +export default function () { + const res = http.get('https://k6.io'); + const doc = parseHTML(res.body); + + const titleDoc = doc.find('head title'); + const title = titleDoc.text(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-first--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-first--.md new file mode 100644 index 0000000000..0c21dc0371 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-first--.md @@ -0,0 +1,53 @@ +--- +title: 'Selection.first()' +excerpt: 'Reduce the set of matched elements to the first in the set.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-first/ +--- + +Reduce the set of matched elements to the first in the set. +Mimics [jquery.first](https://api.jquery.com/first/). + +### Returns + +| Type | Description | +| ---------------------------------------------- | ----------------------------------- | +| [Selection](/javascript-api/k6-html/selection) | The first element of the Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dt'); + + console.log(sel.first().html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-get-index-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-get-index-.md new file mode 100644 index 0000000000..210b945d63 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-get-index-.md @@ -0,0 +1,58 @@ +--- +title: 'Selection.get(index)' +excerpt: 'Retrieve the Element matched by the selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-get/ +--- + +Retrieve the Element matched by the selector. +Mimics [jquery.get](https://api.jquery.com/get/) + +| Parameter | Type | Description | +| --------- | ------ | ---------------------------------------------------------- | +| index | Number | A zero-based integer indicating which element to retrieve. | + +### Returns + +| Type | Description | +| ------- | ------------------------------------ | +| Element | The Element matched by the selector. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dl').children(); + + console.log(sel.get(0).innerHTML()); + console.log(sel.get(1).innerHTML()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-has-selector-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-has-selector-.md new file mode 100644 index 0000000000..ff288ff2c1 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-has-selector-.md @@ -0,0 +1,52 @@ +--- +title: 'Selection.has(selector)' +excerpt: 'Reduce the set of matched elements to those that have a descendant that matches the selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-has/ +--- + +Reduce the set of matched elements to those that have a descendant that matches the selector. +Mimics [jquery.has](https://api.jquery.com/has/). + +| Parameter | Type | Description | +| --------- | ------ | -------------------------------------------------------------------- | +| selector | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2 +
      +
    • list item 2-a
    • +
    • list item 2-b
    • +
    +
  • +
  • list item 3
  • +
  • list item 4
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li').has('ul'); + + console.log(sel.html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-html--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-html--.md new file mode 100644 index 0000000000..c79f582c4f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-html--.md @@ -0,0 +1,53 @@ +--- +title: 'Selection.html()' +excerpt: 'Get the HTML contents of the first element in the set of matched elements.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-html/ +--- + +Get the HTML contents of the first element in the set of matched elements. +Mimics [jquery.html](https://api.jquery.com/html/) + +### Returns + +| Type | Description | +| ------ | --------------------------------------------------------------------- | +| string | The HTML content of the first element in the set of matched elements. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dt'); + + console.log(sel.html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-is-selector-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-is-selector-.md new file mode 100644 index 0000000000..fe396431ef --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-is-selector-.md @@ -0,0 +1,70 @@ +--- +title: 'Selection.is(selector)' +excerpt: 'Check the current matched set of elements against a selector or element and return true if at least one of these elements matches the given arguments.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-is/ +--- + +Check the current matched set of elements against a selector or element and return true if at least one of these elements matches the given arguments. +Mimics [jquery.is](https://api.jquery.com/is/) + +| Parameter | Type | Description | +| --------- | ---------------------------------------------- | -------------------------------------------------------------------- | +| selector | function | A function used as a test for each element in the set | +| selector | string | A string containing a selector expression to match elements against. | +| selector | [Selection](/javascript-api/k6-html/selection) | A selection. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | --------------------- | +| [Selection](/javascript-api/k6-html/selection) | The filter selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + let result; + + const els = doc.find('dl').children(); + + result = els.is('dd'); + console.log(result); + + result = els.is(function (idx, el) { + return el.text() === 'hola'; + }); + console.log(result); + + result = els.is(els.first()); + console.log(result); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-last--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-last--.md new file mode 100644 index 0000000000..40c08d2881 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-last--.md @@ -0,0 +1,53 @@ +--- +title: 'Selection.last()' +excerpt: 'Reduce the set of matched elements to the final one in the set.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-last/ +--- + +Reduce the set of matched elements to the final one in the set. +Mimics [jquery.last](https://api.jquery.com/last/). + +### Returns + +| Type | Description | +| ---------------------------------------------- | ----------------------------------- | +| [Selection](/javascript-api/k6-html/selection) | The final element of the Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dt'); + + console.log(sel.last().html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-map-fn-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-map-fn-.md new file mode 100644 index 0000000000..48eb000250 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-map-fn-.md @@ -0,0 +1,62 @@ +--- +title: 'Selection.map(fn)' +excerpt: 'Pass each selection in the current matched set through a function, producing a new Array containing the return values.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-map/ +--- + +Pass each selection in the current matched set through a function, producing a new Array containing the return values. +Mimics [jquery.each](https://api.jquery.com/each/) + +| Parameter | Type | Description | +| --------- | -------- | ----------------------------------------------------------- | +| fn | function | A function to iterate all the Selections of the Collection. | + +### Returns + +| Type | Description | +| ----- | --------------------------------------- | +| Array | The array containing the return values. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const newEls = doc + .find('dl') + .children() + .map(function (idx, el) { + return 'hola ' + el.text(); + }); + + console.log(newEls); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-next--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-next--selector--.md new file mode 100644 index 0000000000..46f49f29ad --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-next--selector--.md @@ -0,0 +1,49 @@ +--- +title: 'Selection.next([selector])' +excerpt: 'Get the immediately following sibling of each element in the set of matched elements +Mimics jquery.next.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-next/ +--- + +Get the immediately following sibling of each element in the set of matched elements +Mimics [jquery.next](https://api.jquery.com/next/). + +| Parameter | Type | Description | +| ------------------- | ------ | -------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2
  • +
  • list item 3
  • +
  • list item 4
  • +
  • list item 5
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li.third-item').next(); + + console.log(sel.html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-nextAll--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-nextAll--selector--.md new file mode 100644 index 0000000000..7cfbbf3cc6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-nextAll--selector--.md @@ -0,0 +1,48 @@ +--- +title: 'Selection.nextAll([selector])' +excerpt: 'Get all following siblings of each element in the set of matched elements, optionally filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-nextall/ +--- + +Get all following siblings of each element in the set of matched elements, optionally filtered by a selector. +Mimics [jquery.nextAll](https://api.jquery.com/nextAll/). + +| Parameter | Type | Description | +| ------------------- | ------ | ------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2
  • +
  • list item 3
  • +
  • list item 4
  • +
  • list item 5
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li.third-item').nextAll(); + + console.log(sel.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-nextUntil-selector-filter.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-nextUntil-selector-filter.md new file mode 100644 index 0000000000..26e127f65b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-nextUntil-selector-filter.md @@ -0,0 +1,60 @@ +--- +title: 'Selection.nextUntil([selector], [filter])' +excerpt: 'Get all following siblings of each element in the set of matched elements, optionally filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-nextuntil/ +--- + +Get all following siblings of each element up to but not including the element matched by the selector. +Mimics [jquery.nextUntil](https://api.jquery.com/nextUntil/) + +| Parameter | Type | Description | +| ------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------- | +| selector (optional) | string \| [Selection](/javascript-api/k6-html/selection) \| `null` | A selector expression or object to match elements against. | +| filter (optional) | string \| `null` | A selector expression to filter matched elements. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('#term-2').nextUntil('dt'); + console.log(sel.size()); + + const selFilter = doc.find('#term-1').nextUntil('#term-3', 'dd'); + console.log(selFilter.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-not-selector-.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-not-selector-.md new file mode 100644 index 0000000000..b172b72828 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-not-selector-.md @@ -0,0 +1,63 @@ +--- +title: 'Selection.not(selector)' +excerpt: 'Remove elements from the set of matched elements.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-not/ +--- + +Remove elements from the set of matched elements. +Mimics [jquery.not](https://api.jquery.com/not/) + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------------------------------- | +| selector | string | A string containing a selector expression to match elements against. | +| selector | function | A function used as a test for each element in the set. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + let sel = doc.find('dl').children(); + + console.log(sel.not('dt').size()); + + sel = sel.not(function (idx, item) { + return item.text().startsWith('definition'); + }); + + console.log(sel.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parent--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parent--selector--.md new file mode 100644 index 0000000000..88f73f0935 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parent--selector--.md @@ -0,0 +1,48 @@ +--- +title: 'Selection.parent([selector])' +excerpt: 'Get the parent of each element in the current set of matched elements, optionally filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-parent/ +--- + +Get the parent of each element in the current set of matched elements, optionally filtered by a selector. +Mimics [jquery.parent](https://api.jquery.com/parent/). + +| Parameter | Type | Description | +| ------------------- | ------ | -------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2
  • +
  • list item 3
  • +
  • list item 4
  • +
  • list item 5
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li.third-item').parent(); + + console.log(sel.html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parents--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parents--selector--.md new file mode 100644 index 0000000000..163279ce63 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parents--selector--.md @@ -0,0 +1,48 @@ +--- +title: 'Selection.parents([selector])' +excerpt: 'Get the ancestors of each element in the current set of matched elements, optionally filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-parents/ +--- + +Get the ancestors of each element in the current set of matched elements, optionally filtered by a selector. +Mimics [jquery.parents](https://api.jquery.com/parents/). + +| Parameter | Type | Description | +| ------------------- | ------ | -------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2
  • +
  • list item 3
  • +
  • list item 4
  • +
  • list item 5
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li.third-item').parents(); + + console.log(sel.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parentsUntil-selector-filter.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parentsUntil-selector-filter.md new file mode 100644 index 0000000000..406c8f47d1 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-parentsUntil-selector-filter.md @@ -0,0 +1,60 @@ +--- +title: 'Selection.parentsUntil([selector], [filter])' +excerpt: 'Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-parentsuntil/ +--- + +Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector. +Mimics [jquery.parentsUntil](https://api.jquery.com/parentsUntil/) + +| Parameter | Type | Description | +| ------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------- | +| selector (optional) | string \| [Selection](/javascript-api/k6-html/selection) \| `null` | A selector expression or object to match elements against. | +| filter (optional) | string \| `null` | A selector expression to filter matched elements. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('#term-2').parentsUntil('dt'); + console.log(sel.size()); + + const selFilter = doc.find('#term-3').parentsUntil('dt', 'dd'); + console.log(selFilter.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prev--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prev--selector--.md new file mode 100644 index 0000000000..63378dc1b4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prev--selector--.md @@ -0,0 +1,47 @@ +--- +title: 'Selection.prev([selector])' +excerpt: 'Get the immediately preceding sibling of each element in the set of matched elements.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-prev/ +--- + +Get the immediately preceding sibling of each element in the set of matched elements. +Mimics [jquery.prev](https://api.jquery.com/prev/). + +| Parameter | Type | Description | +| ------------------- | ------ | -------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2
  • +
  • list item 3
  • +
  • list item 4
  • +
  • list item 5
  • +
+ `; + const doc = parseHTML(content); + const sel = doc.find('li.third-item').prev(); + + console.log(sel.html()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prevAll--selector--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prevAll--selector--.md new file mode 100644 index 0000000000..a7d0c277eb --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prevAll--selector--.md @@ -0,0 +1,48 @@ +--- +title: 'Selection.prevAll([selector])' +excerpt: 'Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-prevall/ +--- + +Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector. +Mimics [jquery.prevAll](https://api.jquery.com/prevAll/). + +| Parameter | Type | Description | +| ------------------- | ------ | -------------------------------------------------------------------- | +| selector (optional) | string | A string containing a selector expression to match elements against. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
    +
  • list item 1
  • +
  • list item 2
  • +
  • list item 3
  • +
  • list item 4
  • +
  • list item 5
  • +
+ `; + const doc = parseHTML(content); + + const sel = doc.find('li.third-item').prevAll(); + + console.log(sel.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prevUntil-selector-filter.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prevUntil-selector-filter.md new file mode 100644 index 0000000000..1877b3897b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-prevUntil-selector-filter.md @@ -0,0 +1,60 @@ +--- +title: 'Selection.prevUntil([selector], [filter])' +excerpt: 'Get all preceding siblings of each element up to but not including the element matched by the selector.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-prevuntil/ +--- + +Get all preceding siblings of each element up to but not including the element matched by the selector. +Mimics [jquery.prevUntil](https://api.jquery.com/prevUntil/). + +| Parameter | Type | Description | +| ------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------- | +| selector (optional) | string \| [Selection](/javascript-api/k6-html/selection) \| `null` | A selector expression or object to match elements against. | +| filter (optional) | string \| `null` | A selector expression to filter matched elements. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('#term-2').prevUntil('dt'); + console.log(sel.size()); + + const selFilter = doc.find('#term-3').prevUntil('#term-1', 'dd'); + console.log(selFilter.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serialize--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serialize--.md new file mode 100644 index 0000000000..21d3267c13 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serialize--.md @@ -0,0 +1,39 @@ +--- +title: 'Selection.serialize()' +excerpt: 'Encode a set of form elements as a string in standard URL-encoded notation for submission.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-serialize/ +--- + +Encode a set of form elements as a string in standard URL-encoded notation for submission. +Mimics [jquery.serialize](https://api.jquery.com/serialize/) + +### Returns + +| Type | Description | +| ------ | -------------------------------------------------------------------- | +| string | The URL-encoded representation of the matched form or form elements. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+ `; + + const doc = parseHTML(content); + const sel = doc.find('form'); + const serialized = sel.serialize(); + + console.log(serialized); // "username=" + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serializeArray--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serializeArray--.md new file mode 100644 index 0000000000..2399a789bc --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serializeArray--.md @@ -0,0 +1,39 @@ +--- +title: 'Selection.serializeArray()' +excerpt: 'Encode a set of form elements as an array of names and values.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-serializearray/ +--- + +Encode a set of form elements as an array of names and values (`[{ name: "name", value: "value" }, ...]`). +Mimics [jquery.serializeArray](https://api.jquery.com/serializeArray/) + +### Returns + +| Type | Description | +| ----- | --------------------------------------------------------------- | +| array | Array of names and values of the matched form or form elements. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+ `; + + const doc = parseHTML(content); + const sel = doc.find('form'); + const serialized = sel.serializeArray(); + + console.log(JSON.stringify(serialized)); // [{"name": "username", "value": ""}] + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serializeObject--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serializeObject--.md new file mode 100644 index 0000000000..b67a3bb97d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-serializeObject--.md @@ -0,0 +1,38 @@ +--- +title: 'Selection.serializeObject()' +excerpt: 'Encode a set of form elements as an object.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-serializeobject/ +--- + +Encode a set of form elements as an object (`{ "inputName": "value", "checkboxName": "value" }`). + +### Returns + +| Type | Description | +| ------ | ------------------------------------------------------------------------------------------------------- | +| object | Object representation of the matched form or form elements, key is field name and value is field value. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+ `; + + const doc = parseHTML(content); + const sel = doc.find('form'); + const serialized = sel.serializeObject(); + + console.log(JSON.stringify(serialized)); // {"username": ""} + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-size--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-size--.md new file mode 100644 index 0000000000..c3a2f0ba4a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-size--.md @@ -0,0 +1,53 @@ +--- +title: 'Selection.size()' +excerpt: 'Return the number of elements in the Selection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-size/ +--- + +Return the number of elements in the Selection. +Mimics [jquery.size](https://api.jquery.com/size/) + +### Returns + +| Type | Description | +| ------ | ---------------------------------------- | +| Number | The number of elements in the Selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const sel = doc.find('dt'); + + console.log(sel.size()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-slice-start -- end--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-slice-start -- end--.md new file mode 100644 index 0000000000..cc9d6765ea --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-slice-start -- end--.md @@ -0,0 +1,61 @@ +--- +title: 'Selection.slice(start [, end])' +excerpt: 'Reduce the set of matched elements to a subset specified by a range of indices.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-slice/ +--- + +Reduce the set of matched elements to a subset specified by a range of indices. +Mimics [jquery.slice](https://api.jquery.com/slice/) + +| Parameter | Type | Description | +| --------- | ---------------------------------------------- | -------------------------------------------------------------------------------------- | +| start | Number | An integer indicating the 0-based position at which the elements begin to be selected. | +| end | Number | An integer indicating the 0-based position at which the elements stop being selected. | +| selector | [Selection](/javascript-api/k6-html/selection) | A selection. | + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------------ | +| [Selection](/javascript-api/k6-html/selection) | The new selection. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + const els = doc.find('dl').children(); + + console.log(els.slice(4).text()); + + console.log(els.slice(2, 4).text()); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-text--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-text--.md new file mode 100644 index 0000000000..0a8321143c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-text--.md @@ -0,0 +1,31 @@ +--- +title: 'Selection.text()' +excerpt: 'Get the text content of the Selection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-text/ +--- + +Get the text content of the Selection. +Mimics [jquery.text](https://api.jquery.com/text/). + +### Returns + +| Type | Description | +| ------ | ----------------------- | +| string | Selection text content. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import http from 'k6/http'; + +export default function () { + const res = http.get('https://k6.io'); + const doc = parseHTML(res.body); + const pageTitle = doc.find('head title').text(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-toArray--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-toArray--.md new file mode 100644 index 0000000000..64d72525da --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-toArray--.md @@ -0,0 +1,57 @@ +--- +title: 'Selection.toArray()' +excerpt: 'Retrieve all the elements contained in the Selection, as an array.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-toarray/ +--- + +Retrieve all the elements contained in the Selection, as an array. +Mimics [jquery.toArray](https://api.jquery.com/toArray/). + +### Returns + +| Type | Description | +| ------------------------------------------------------- | --------------------------- | +| Array of [Selection](/javascript-api/k6-html/selection) | Array of Selection objects. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` +
+
term 1
+
definition 1-a
+
definition 1-b
+
definition 1-c
+
definition 1-d
+ +
term 2
+
definition 2-a
+
definition 2-b
+
definition 2-c
+ +
term 3
+
definition 3-a
+
definition 3-b
+
+ `; + const doc = parseHTML(content); + + doc + .find('dl') + .children() + .toArray() + .forEach(function (item) { + console.log(item.text()); + }); + + sleep(1); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-val--.md b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-val--.md new file mode 100644 index 0000000000..bafde1a74e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/08 k6-html/50 Selection/Selection-val--.md @@ -0,0 +1,55 @@ +--- +title: 'Selection.val()' +excerpt: 'Get the current value of the first element in the set of matched elements.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-val/ +--- + +Get the current value of the first element in the set of matched elements. +Mimics [jquery.val](https://api.jquery.com/val/). + +### Returns + +| Type | Description | +| ------ | -------------------------------------------------------------- | +| string | The value of the first element in the set of matched elements. | + +### Example + + + +```javascript +import { parseHTML } from 'k6/html'; +import { sleep } from 'k6'; + +export default function () { + const content = ` + + + + + + `; + const doc = parseHTML(content); + + console.log(doc.find('#text_input').val()); + console.log(doc.find('#select_one option[selected]').val()); + console.log(doc.find('#select_one').val()); + console.log(doc.find('#select_text').val()); + console.log(doc.find('#select_multi').val()); + console.log(doc.find('#textarea').val()); + + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http.md b/src/data/markdown/docs/02 javascript api/09 k6-http.md index 3a66109c41..e266a3a6dd 100644 --- a/src/data/markdown/docs/02 javascript api/09 k6-http.md +++ b/src/data/markdown/docs/02 javascript api/09 k6-http.md @@ -2,7 +2,31 @@ title: 'k6/http' excerpt: 'The k6/http module contains functionality for performing HTTP transactions.' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-http/ --- The k6/http module contains functionality for performing HTTP transactions. + +| Function | Description | +| -------- | ----------- | +| [batch( requests )](/javascript-api/k6-http/batch) | Issue multiple HTTP requests in parallel (like e.g. browsers tend to do). | +| [cookieJar()](/javascript-api/k6-http/cookiejar-method) | Get active HTTP Cookie jar. | +| [del( url, [body], [params] )](/javascript-api/k6-http/del) | Issue an HTTP DELETE request. | +| [file( data, [filename], [contentType] )](/javascript-api/k6-http/file) | Create a file object that is used for building multi-part requests. | +| [get( url, [params] )](/javascript-api/k6-http/get) | Issue an HTTP GET request. | +| [head( url, [params] )](/javascript-api/k6-http/head) | Issue an HTTP HEAD request. | +| [options( url, [body], [params] )](/javascript-api/k6-http/options) | Issue an HTTP OPTIONS request. | +| [patch( url, [body], [params] )](/javascript-api/k6-http/patch) | Issue an HTTP PATCH request. | +| [post( url, [body], [params] )](/javascript-api/k6-http/post) | Issue an HTTP POST request. | +| [put( url, [body], [params] )](/javascript-api/k6-http/put) | Issue an HTTP PUT request. | +| [request( method, url, [body], [params] )](/javascript-api/k6-http/request) | Issue any type of HTTP request. | +| [asyncRequest( method, url, [body], [params] )](/javascript-api/k6-http/asyncrequest) | Issue any type of HTTP request asynchronously. | +| [setResponseCallback(expectedStatuses)](/javascript-api/k6-http/setresponsecallback) | Sets a response callback to mark responses as expected. | +| [url\`url\`](/javascript-api/k6-http/urlurl) | Creates a URL with a name tag. Read more on [URL Grouping](/using-k6/http-requests#url-grouping). | +| [expectedStatuses( statusCodes )](/javascript-api/k6-http/expectedstatuses) | Create a callback for setResponseCallback that checks status codes. | + +| Class | Description | +| -------- | ----------- | +| [CookieJar](/javascript-api/k6-http/cookiejar) | Used for storing cookies, set by the server and/or added by the client. | +| [FileData](/javascript-api/k6-http/filedata) | Used for wrapping data representing a file when doing multipart requests (file uploads). | +| [Params](/javascript-api/k6-http/params) | Used for setting various HTTP request-specific parameters such as headers, cookies, etc. | +| [Response](/javascript-api/k6-http/response) | Returned by the http.* methods that generate HTTP requests. | diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-asyncRequest- method- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-asyncRequest- method- url- -body-- -params- -.md new file mode 100644 index 0000000000..59f36f3184 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-asyncRequest- method- url- -body-- -params- -.md @@ -0,0 +1,90 @@ +--- +title: 'asyncRequest( method, url, [body], [params] )' +description: 'Issue any type of HTTP request asynchronously.' +excerpt: 'Issue any type of HTTP request asynchronously.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/asyncrequest/ +--- + +| Parameter | Type | Description | +| ----------------- | ----------------------------- | ----------------------------------------------------------------------------------------- | +| method | string | Request method (e.g. `'POST'`). Must be uppercase. | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `'http://example.com'`). | +| body (optional) | string / object / ArrayBuffer | Request body. Objects will be `x-www-form-urlencoded` encoded. | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------- | --------------------------------------------------------- | +| Promise with Response | HTTP [Response](/javascript-api/k6-http/response) object. | + +### Examples + +Using http.asyncRequest() to issue a POST request: + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/post'; + +export default async function () { + const data = { name: 'Bert' }; + + // Using a JSON string as body + let res = await http.asyncRequest('POST', url, JSON.stringify(data), { + headers: { 'Content-Type': 'application/json' }, + }); + console.log(res.json().json.name); // Bert + + // Using an object as body, the headers will automatically include + // 'Content-Type: application/x-www-form-urlencoded'. + res = await http.asyncRequest('POST', url, data); + console.log(res.json().form.name); // Bert +} +``` + + + +Using `http.asyncRequest()` to issue multiple requests, then [Promise.race](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race) to determine which requests finish first: + + + +```javascript +import http from 'k6/http'; + +export default async () => { + const urlOne = `https://httpbin.test.k6.io/delay/${randomInt(1, 5)}` + const urlTwo = `https://httpbin.test.k6.io/delay/${randomInt(1, 5)}` + const urlThree = `https://httpbin.test.k6.io/delay/${randomInt(1, 5)}` + + const one = http.asyncRequest('GET', urlOne); + const two = http.asyncRequest('GET', urlTwo); + const three = http.asyncRequest('GET', urlThree); + + console.log('Racing:') + console.log(urlOne); + console.log(urlTwo); + console.log(urlThree); + + const res = await Promise.race([one, two, three]) + console.log('winner is', res.url, 'with duration of', res.timings.duration+'ms'); +} + +function randomInt(min, max) { + return Math.floor(Math.random() * (max - min) + min); +} +``` + +
+ + `http.asyncRequest` has no current way to abort a request. + + In the preceding script, after `res` gets the value from the fastest request, the other requests will continue to execute. + This might block the end of the iteration, because the iteration only stops once all async jobs finish. + +
+ + +
diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-batch- requests -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-batch- requests -.md new file mode 100644 index 0000000000..6d630613fe --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-batch- requests -.md @@ -0,0 +1,181 @@ +--- +title: 'batch( requests )' +description: 'Issue multiple HTTP requests in parallel (like e.g. browsers tend to do).' +excerpt: 'Issue multiple HTTP requests in parallel (like e.g. browsers tend to do).' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/batch/ +--- + +Batch multiple HTTP requests together to issue them in parallel over multiple TCP connections. +To set batch size, use the [batch per host](/using-k6/k6-options/reference/#batch-per-host) option. + +| Parameter | Type | Description | +| --------- | --------------- | ---------------------------------------------------------------- | +| requests | array \| object | An array or object containing requests, in string or object form | + +### Request definition + +You have multiple ways to structure batch requests: +- In an array of arrays +- As an object or array of objects +- As an array of URL strings + +Defining batch requests as URL strings is a shortcut for GET requests. +You can use this GET shortcut in objects—name a key and give it a URL value +(refer to subsequent sections for example syntax). + +#### Array and Object + +You can define a request specified as an array or object with the following parameters. + +
+ +When you define requests as an array, you must use a specific order of items. +Note the `Position` column for the correct order. + +
+ +| Array position | Name | Type | Description | +| -------- | ----------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------- | +| 1 | method | string | Mandatory. The HTTP method of the request. One of GET, POST, PUT, PATCH, DELETE, HEAD or OPTION. | +| 2 | url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Mandatory. The URL to request. | +| 3 | body (optional) | string / object / ArrayBuffer | The body of the request if relevant. Can be set to `null` if not applicable but you want to set the last `params` argument. | +| 4 | params (optional) | object | [Params](/javascript-api/k6-http/params) like auth, custom headers and tags. | + + +#### String + +If you pass an array of string values, k6 automatically parses them into a batch of `GET` requests, where the target is the value of the strings. + +### Returns + +| Type | Description | +| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| object | The returned object contains [Response](/javascript-api/k6-http/response) objects.

It is an array when users pass an array as `requests`, and is an ordinary object with string keys when named requests are used (see below). | + +### Example with arrays + +This example batches three URLs in arrays for parallel fetching: + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const responses = http.batch([ + ['GET', 'https://test.k6.io', null, { tags: { ctype: 'html' } }], + ['GET', 'https://test.k6.io/style.css', null, { tags: { ctype: 'css' } }], + ['GET', 'https://test.k6.io/images/logo.png', null, { tags: { ctype: 'images' } }], + ]); + check(responses[0], { + 'main page status was 200': (res) => res.status === 200, + }); +} +``` + + + +### Example with request objects + +This example uses objects to define a batch of POST requests (along with custom HTTP headers in a [Params](/javascript-api/k6-http/params) object to the request): + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const req1 = { + method: 'GET', + url: 'https://httpbin.test.k6.io/get', + }; + const req2 = { + method: 'GET', + url: 'https://test.k6.io', + }; + const req3 = { + method: 'POST', + url: 'https://httpbin.test.k6.io/post', + body: { + hello: 'world!', + }, + params: { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + }, + }; + const responses = http.batch([req1, req2, req3]); + // httpbin.test.k6.io should return our POST data in the response body, so + // we check the third response object to see that the POST worked. + check(responses[2], { + 'form data OK': (res) => JSON.parse(res.body)['form']['hello'] == 'world!', + }); +} +``` + + + +
+ +In the preceding example, `req1` can happen before `req2` or `req3`. + +
+ +### Example with array of strings + +This example uses an array of URL strings to send a batch of GET requests. + + + +```javascript +import { check } from 'k6'; +import http from 'k6/http'; + +export default function () { + const responses = http.batch(['http://test.k6.io', 'http://test.k6.io/pi.php']); + + check(responses[0], { + 'main page 200': (res) => res.status === 200, + }); + + check(responses[1], { + 'pi page 200': (res) => res.status === 200, + 'pi page has right content': (res) => res.body === '3.14', + }); +} +``` + + + +### Example object with named properties + +Finally, you can also send in named requests by using an object instead of an array as the parameter to `http.batch()`. +This example mixes string URLs and request objects. + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const requests = { + 'front page': 'https://k6.io', + 'features page': { + method: 'GET', + url: 'https://k6.io/features', + params: { headers: { 'User-Agent': 'k6' } }, + }, + }; + const responses = http.batch(requests); + // when accessing results, we use the name of the request as index + // in order to find the corresponding Response object + check(responses['front page'], { + 'front page status was 200': (res) => res.status === 200, + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-cookieJar--.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-cookieJar--.md new file mode 100644 index 0000000000..82572d6f0b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-cookieJar--.md @@ -0,0 +1,27 @@ +--- +title: 'cookieJar()' +slug: '/javascript-api/k6-http/cookiejar-method' +description: 'Get active HTTP Cookie jar.' +excerpt: 'Get active HTTP Cookie jar.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/cookiejar-method/ +--- + +Get the active cookie jar. + +| Type | Description | +| ---------------------------------------------- | ------------------- | +| [CookieJar](/javascript-api/k6-http/cookiejar) | A CookieJar object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +export default function () { + const jar = http.cookieJar(); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-del- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-del- url- -body-- -params- -.md new file mode 100644 index 0000000000..e453253ec7 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-del- url- -body-- -params- -.md @@ -0,0 +1,37 @@ +--- +title: 'del( url, [body], [params] )' +description: 'Issue an HTTP DELETE request.' +excerpt: 'Issue an HTTP DELETE request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/del/ +--- + +Make a DELETE request. + +| Parameter | Type | Description | +| ---------------------------- | --------------- | ----------------------------------------------------------------------------------------- | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| body (optional, discouraged) | string / object / ArrayBuffer | Request body; objects will be `x-www-form-urlencoded`. This is discouraged, because sending a DELETE request with a body has [no defined semantics](https://tools.ietf.org/html/rfc7231#section-4.3.5) and may cause some servers to reject it. | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------- | --------------------------------------------------------- | +| Response | HTTP [Response](/javascript-api/k6-http/response) object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/delete'; + +export default function () { + const params = { headers: { 'X-MyHeader': 'k6test' } }; + http.del(url, null, params); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-file- data- -filename-- -contentType- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-file- data- -filename-- -contentType- -.md new file mode 100644 index 0000000000..dd52ca2481 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-file- data- -filename-- -contentType- -.md @@ -0,0 +1,41 @@ +--- +title: 'file( data, [filename], [contentType] )' +description: 'Create a file object that is used for building multi-part requests.' +excerpt: 'Create a file object that is used for building multi-part requests.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/file/ +--- + +Create a file object that is used for building [Multipart requests (file uploads)](/examples/data-uploads#multipart-request-uploading-a-file). + +| Parameter | Type | Description | +| ----------- | ---------------------------- | -------------------------------------------------------------------------------- | +| data | string / Array / ArrayBuffer | File data as string, array of numbers, or an `ArrayBuffer` object. | +| filename | string | The filename to specify for this field (or "part") of the multipart request. | +| contentType | string | The content type to specify for this field (or "part") of the multipart request. | + +### Returns + +| Type | Description | +| -------------------------------------------- | ------------------ | +| [FileData](/javascript-api/k6-http/filedata) | A FileData object. | + +### Example + + + +```javascript +import { sleep } from 'k6'; +import { md5 } from 'k6/crypto'; +import http from 'k6/http'; + +const binFile = open('/path/to/file.bin', 'b'); + +export default function () { + const f = http.file(binFile, 'test.bin'); + console.log(md5(f.data, 'hex')); + console.log(f.filename); + console.log(f.content_type); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-get- url- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-get- url- -params- -.md new file mode 100644 index 0000000000..c75fc22a54 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-get- url- -params- -.md @@ -0,0 +1,34 @@ +--- +title: 'get( url, [params] )' +description: 'Issue an HTTP GET request.' +excerpt: 'Issue an HTTP GET request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/get/ +--- + +Make a GET request. + +| Parameter | Type | Description | +| ----------------- | ------ | ----------------------------------------------------------------------------------------- | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| [Response](/javascript-api/k6-http/response) | HTTP Response object. | + +### Example fetching a URL + + + +```javascript +import http from 'k6/http'; + +export default function () { + const res = http.get('https://test.k6.io'); + console.log(JSON.stringify(res.headers)); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-haed- url- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-haed- url- -params- -.md new file mode 100644 index 0000000000..a6f944ad21 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-haed- url- -params- -.md @@ -0,0 +1,34 @@ +--- +title: 'head( url, [params] )' +description: 'Issue an HTTP HEAD request.' +excerpt: 'Issue an HTTP HEAD request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/head/ +--- + +Make a HEAD request. + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| [Response](/javascript-api/k6-http/response) | HTTP Response object. | + +### Example fetching a URL + + + +```javascript +import http from 'k6/http'; + +export default function () { + const res = http.head('https://test.k6.io'); + console.log(JSON.stringify(res.headers)); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-options- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-options- url- -body-- -params- -.md new file mode 100644 index 0000000000..97d45198d3 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-options- url- -body-- -params- -.md @@ -0,0 +1,38 @@ +--- +title: "options( url, [body], [params] )" +description: "Issue an HTTP OPTIONS request." +excerpt: "Issue an HTTP OPTIONS request." +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/options/ +--- + +| Parameter | Type | Description | +| ----------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------- | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| body (optional) | string / object / ArrayBuffer | Request body; objects will be `x-www-form-urlencoded`. | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + + +### Returns + +| Type | Description | +| -------- | --------------------------------------------------------------------- | +| Response | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/'; + +export default function () { + const params = { headers: { 'X-MyHeader': 'k6test' } }; + const res = http.options(url, null, params); + console.log(res.headers['Allow']); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-patch- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-patch- url- -body-- -params- -.md new file mode 100644 index 0000000000..2397b99776 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-patch- url- -body-- -params- -.md @@ -0,0 +1,39 @@ +--- +title: 'patch( url, [body], [params] )' +description: 'Issue an HTTP PATCH request.' +excerpt: 'Issue an HTTP PATCH request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/patch/ +--- + +| Parameter | Type | Description | +| ----------------- | ----------------------------- | ---------------------------------------------------------------------------------------- | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| body (optional) | string / object / ArrayBuffer | Request body; objects will be `x-www-form-urlencoded`. | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| [Response](/javascript-api/k6-http/response) | HTTP Response object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/patch'; + +export default function () { + const headers = { 'Content-Type': 'application/json' }; + const data = { name: 'Bert' }; + + const res = http.patch(url, JSON.stringify(data), { headers: headers }); + + console.log(JSON.parse(res.body).json.name); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-post- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-post- url- -body-- -params- -.md new file mode 100644 index 0000000000..2aad946264 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-post- url- -body-- -params- -.md @@ -0,0 +1,55 @@ +--- +title: 'post( url, [body], [params] )' +description: 'Issue an HTTP POST request.' +excerpt: 'Issue an HTTP POST request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/post/ +--- + +| Parameter | Type | Description | +| ------------------- | ----------------------------- | ---------------------------------------------------------------------------------------- | +| `url` | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| `body` | string / object / ArrayBuffer | Request body; objects will be `x-www-form-urlencoded`. | +| `params` (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters | + +### Returns + +| Type | Description | +| ---------- | --------------------------------------------------------- | +| `Response` | HTTP [Response](/javascript-api/k6-http/response) object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/post'; +const logoBin = open('./logo.png', 'b'); + +export default function () { + let data = { name: 'Bert' }; + + // Using a JSON string as body + let res = http.post(url, JSON.stringify(data), { + headers: { 'Content-Type': 'application/json' }, + }); + console.log(res.json().json.name); // Bert + + // Using an object as body, the headers will automatically include + // 'Content-Type: application/x-www-form-urlencoded'. + res = http.post(url, data); + console.log(res.json().form.name); // Bert + + // Using a binary array as body. Make sure to open() the file as binary + // (with the 'b' argument). + http.post(url, logoBin, { headers: { 'Content-Type': 'image/png' } }); + + // Using an ArrayBuffer as body. Make sure to pass the underlying ArrayBuffer + // instance to http.post(), and not the TypedArray view. + data = new Uint8Array([104, 101, 108, 108, 111]); + http.post(url, data.buffer, { headers: { 'Content-Type': 'image/png' } }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-put- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-put- url- -body-- -params- -.md new file mode 100644 index 0000000000..4be880d25b --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-put- url- -body-- -params- -.md @@ -0,0 +1,39 @@ +--- +title: 'put( url, [body], [params] )' +description: 'Issue an HTTP PUT request.' +excerpt: 'Issue an HTTP PUT request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/put/ +--- + +| Parameter | Type | Description | +| ----------------- | ----------------------------- | ----------------------------------------------------------------------------------------- | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `http://example.com`). | +| body (optional) | string / object / ArrayBuffer | Request body; objects will be `x-www-form-urlencoded`. | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------- | --------------------------------------------------------- | +| Response | HTTP [Response](/javascript-api/k6-http/response) object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/put'; + +export default function () { + const headers = { 'Content-Type': 'application/json' }; + const data = { name: 'Bert' }; + + const res = http.put(url, JSON.stringify(data), { headers: headers }); + + console.log(JSON.parse(res.body).json.name); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-request- method- url- -body-- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-request- method- url- -body-- -params- -.md new file mode 100644 index 0000000000..e5c0fccad1 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-request- method- url- -body-- -params- -.md @@ -0,0 +1,48 @@ +--- +title: 'request( method, url, [body], [params] )' +description: 'Issue any type of HTTP request.' +excerpt: 'Issue any type of HTTP request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/request/ +--- + +| Parameter | Type | Description | +| ----------------- | ----------------------------- | ----------------------------------------------------------------------------------------- | +| method | string | Request method (e.g. `'POST'`). Must be uppercase. | +| url | string / [HTTP URL](/javascript-api/k6-http/urlurl#returns) | Request URL (e.g. `'http://example.com'`). | +| body (optional) | string / object / ArrayBuffer | Request body; Objects will be `x-www-form-urlencoded` encoded. | +| params (optional) | object | [Params](/javascript-api/k6-http/params) object containing additional request parameters. | + +### Returns + +| Type | Description | +| -------- | --------------------------------------------------------- | +| Response | HTTP [Response](/javascript-api/k6-http/response) object. | + +### Example + +Using http.request() to issue a POST request: + + + +```javascript +import http from 'k6/http'; + +const url = 'https://httpbin.test.k6.io/post'; + +export default function () { + const data = { name: 'Bert' }; + + // Using a JSON string as body + let res = http.request('POST', url, JSON.stringify(data), { + headers: { 'Content-Type': 'application/json' }, + }); + console.log(res.json().json.name); // Bert + + // Using an object as body, the headers will automatically include + // 'Content-Type: application/x-www-form-urlencoded'. + res = http.request('POST', url, data); + console.log(res.json().form.name); // Bert +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-set-response-callback-expectedStatuses.md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-set-response-callback-expectedStatuses.md new file mode 100644 index 0000000000..1d1b98ea9e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-set-response-callback-expectedStatuses.md @@ -0,0 +1,53 @@ +--- +title: 'setResponseCallback( callback )' +description: 'set responseCallback to mark responses as expected' +excerpt: 'set responseCallback to mark responses as expected' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/set-response-callback/ +--- + +Set the response callback to be called to determine if a response was expected/successful or not. + +The result of this is that requests will be tagged with `expected_response` `"true"` or `"false"` and `http_req_failed` will be emitted with the reverse. This does include all redirects so if for a request only 200 is the expected response and there is 301 redirect before that, the redirect will be marked as failed as only status code 200 was marked as expected. + +#### Exceptions + +Due to implementation specifics: +- Requests with authentication `digest` are always expected to first get 401 and then to get whatever was specified. +- Requests with authentication `ntlm` will let a 401 status code on the first request as well as anything defined by `expectedStatuses` + + +| Parameter | Type | Description | +| --------- | --------------- | ---------------------------------------------------------------- | +| callback | [expectedStatuses](/javascript-api/k6-http/expectedstatuses) | an object returned from [expectedStatuses](/javascript-api/k6-http/expectedstatuses) | + +Currently only the very special [expectedStatuses](/javascript-api/k6-http/expectedstatuses) objects are supported but in the future it is planned that a JavaScript callback will be supported as well. By default requests with status codes between 200 and 399 are considered "expected". + +Setting the callback to `null` disables the tagging with `expected_response` and the emitting of `http_req_failed`. + +It is recommended that if a per request responseCallback is used with [Params](/javascript-api/k6-http/params) it is actually defined once and used instead of creating it on each request. + +### Example + + + +```javascript +import http from 'k6/http'; + +http.setResponseCallback(http.expectedStatuses({ min: 200, max: 300 })); + +const only300Callback = http.expectedStatuses(300); + +export default () => { + // this will use the default response callback and be marked as successful + http.get('https://httpbin.test.k6.io/status/200'); + + // this will be marked as a failed request as it won't get the expected status code of 300 + http.get('https://httpbin.test.k6.io/status/200', { responseCallback: only300Callback }); + + http.setResponseCallback(http.expectedStatuses(301)); + // from here on for this VU only the 301 status code will be successful so on the next iteration of + // the VU the first request will be marked as failure +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/10-url- url- .md b/src/data/markdown/docs/02 javascript api/09 k6-http/10-url- url- .md new file mode 100644 index 0000000000..cafee8568d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/10-url- url- .md @@ -0,0 +1,35 @@ +--- +title: 'url`url`' +description: 'Creates a URL with a name tag.' +excerpt: 'Creates a URL with a name tag.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/url/ +--- + +URLs that contain dynamic parts can introduce a large number of unique URLs in the metrics stream. You can use `http.url` to set a consistent name tag in your requests to remedy this issue. Read more on [URL Grouping](/using-k6/http-requests#url-grouping). + +| Parameter | Type | Description | +| --------- | --------------- | ---------------------------------------------------------------- | +| url | template literal | Request URL (e.g. `http://example.com`). | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| HTTP URL | HTTP URL object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +export default function () { + for (let id = 1; id <= 100; id++) { + // tags.name="https://test.k6.io?id=${}", + http.get(http.url`https://test.k6.io?id=${id}`); + } +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/11-expected-statuses.md b/src/data/markdown/docs/02 javascript api/09 k6-http/11-expected-statuses.md new file mode 100644 index 0000000000..725a95b605 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/11-expected-statuses.md @@ -0,0 +1,36 @@ +--- +title: 'expectedStatuses( statuses )' +description: 'generates a responseCallback to check status codes' +excerpt: 'generates a responseCallback to check status codes' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/expected-statuses/ +--- + +Returns a callback to be used with [setResponseCallback](/javascript-api/k6-http/setresponsecallback) to mark responses as expected based only on their status codes. + + +| Parameter | Type | Description | +| --------- | --------------- | ---------------------------------------------------------------- | +| statuses | integer/objects | either an integer or an object like {min:100, max:300} which gives a minimum and maximum expected status codes| + +You can have as many arguments as wanted in any order. + +### Example + + + +```javascript +import http from 'k6/http'; + +// setting some pretty strange status codes as expected +http.setResponseCallback( + http.expectedStatuses(406, 500, { min: 200, max: 204 }, 302, { min: 305, max: 405 }) +); + +export default () => { + // this one will actually be marked as failed as it doesn't match any of the above listed status + // codes + http.get('https://httpbin.test.k6.io/status/205'); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar.md new file mode 100644 index 0000000000..9f99eaf3b4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar.md @@ -0,0 +1,48 @@ +--- +title: 'CookieJar' +head_title: 'CookieJar object' +description: 'Used for storing cookies, set by the server and/or added by the client.' +excerpt: 'Used for storing cookies, set by the server and/or added by the client.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/cookiejar/ +--- + +_CookieJar_ is an object for storing cookies that are set by the server, added by the client, or both. As described in the how-to guide on using [Cookies](/using-k6/cookies), k6 handles cookies automatically by default. If you need more control over cookies you can however create your own cookie jar and select it as the active jar (instead of the default one created by k6) for one or more requests. + +| Method | Description | +| ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| [cookiesForURL(url)](/javascript-api/k6-http/cookiejar/cookiejar-cookiesforurl) | Get Object of cookies where the key is the cookie name and the value is an array. | +| [set(url, name, value, [options])](/javascript-api/k6-http/cookiejar/cookiejar-set) | Set a cookie in the jar by specifying name, value and some other optional settings like domain, path etc. | +| [clear(url)](/javascript-api/k6-http/cookiejar/cookiejar-clear) | Delete all cookies for the given URL. | +| [delete(url, name)](/javascript-api/k6-http/cookiejar/cookiejar-delete) | Deletes the `name` cookie for the given URL. | + + +### Example + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const res1 = http.get('https://httpbin.test.k6.io/cookies/set?my_cookie=hello%20world', { + redirects: 0, + }); + const jar = http.cookieJar(); + const cookies = jar.cookiesForURL('https://httpbin.test.k6.io/'); + check(res1, { + "has cookie 'my_cookie'": (r) => cookies.my_cookie.length > 0, + 'cookie has correct value': (r) => cookies.my_cookie[0] === 'hello world', + }); + + jar.clear('https://httpbin.test.k6.io/cookies'); + + const res2 = http.get('https://httpbin.test.k6.io/cookies'); + check(res2, { + 'has status 200': (r) => r.status === 200, + "hasn't cookie 'my_cookie'": (r) => r.json().cookies.my_cookie == null, + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-clear-url.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-clear-url.md new file mode 100644 index 0000000000..f8ad5e193f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-clear-url.md @@ -0,0 +1,46 @@ +--- +title: 'CookieJar.clear(url)' +excerpt: 'Delete all cookies for the given URL.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/cookiejar/cookiejar-clear/ +--- + +| Parameter | Type | Description | +| --------- | ------ | ----------- | +| url | string | The URL to delete all cookies for. | + +### Example + + + +```javascript +import http from 'k6/http'; + +export default function () { + http.get('https://httpbin.test.k6.io/cookies/set?one=1&two=2'); + + // We'll use httpbin's reflection to see what cookies we + // are actually sending to the server after every change + let httpbinResp; + httpbinResp = http.get('https://httpbin.test.k6.io/cookies'); + console.log(JSON.stringify(httpbinResp.json().cookies)); + // Will print '{"one":"1","two":"2"}' + + const jar = http.cookieJar(); // get the VU specific jar + jar.set('https://httpbin.test.k6.io/cookies', 'three', '3'); + httpbinResp = http.get('https://httpbin.test.k6.io/cookies'); + console.log(JSON.stringify(httpbinResp.json().cookies)); + // Will print '{"one":"1","three":"3","two":"2"}' + + jar.delete('https://httpbin.test.k6.io/cookies', 'one'); + httpbinResp = http.get('https://httpbin.test.k6.io/cookies'); + console.log(JSON.stringify(httpbinResp.json().cookies)); + // Will print '{"three":"3","two":"2"}' + + jar.clear('https://httpbin.test.k6.io/cookies'); + httpbinResp = http.get('https://httpbin.test.k6.io/cookies'); + console.log(JSON.stringify(httpbinResp.json().cookies)); + // Will print '{}' +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-cookiesForUrl-url.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-cookiesForUrl-url.md new file mode 100644 index 0000000000..3b2312ddd4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-cookiesForUrl-url.md @@ -0,0 +1,38 @@ +--- +title: 'CookieJar.cookiesForURL(url)' +excerpt: 'Get object with all cookies for the given URL, where the key is the cookie name and the value is an array.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/cookiejar/cookiejar-cookiesforurl/ +--- + +| Parameter | Type | Description | +| --------- | ------ | ----------- | +| url | string | The URL to get cookies for. | + +### Returns + +| Type | Description | +| ------ | ----------- | +| object | A JS object with all cookies for the given URL, where the key is the cookie name and the value is an array. | + +### Example + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const res = http.get('https://httpbin.test.k6.io/cookies/set?my_cookie=hello%20world', { + redirects: 0, + }); + const jar = http.cookieJar(); + const cookies = jar.cookiesForURL('https://httpbin.test.k6.io/'); + check(res, { + "has cookie 'my_cookie'": (r) => cookies.my_cookie.length > 0, + 'cookie has correct value': (r) => cookies.my_cookie[0] === 'hello world', + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-delete-url-name.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-delete-url-name.md new file mode 100644 index 0000000000..1100da1b64 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-delete-url-name.md @@ -0,0 +1,46 @@ +--- +title: 'CookieJar.delete(url, name)' +excerpt: 'Delete a cookie of a specified `name` for the given URL.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/cookiejar/cookiejar-delete/ +--- + +| Parameter | Type | Description | +| --------- | ------ | ----------- | +| url | string | The URL to delete cookies for. | +| name | string | The name of the cookie you want to delete. | + +### Example + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const jar = http.cookieJar(); + jar.set('https://httpbin.test.k6.io/cookies', 'my_cookie_1', 'hello world_1'); + jar.set('https://httpbin.test.k6.io/cookies', 'my_cookie_2', 'hello world_2'); + + const res1 = http.get('https://httpbin.test.k6.io/cookies'); + check(res1, { + 'res1 has status 200': (r) => r.status === 200, + "res1 has cookie 'my_cookie_1'": (r) => r.json().cookies.my_cookie_1 !== null, + 'res1 cookie has correct value_1': (r) => r.json().cookies.my_cookie_1 == 'hello world_1', + "res1 has cookie 'my_cookie_2'": (r) => r.json().cookies.my_cookie_2 !== null, + 'res1 cookie has correct value_2': (r) => r.json().cookies.my_cookie_2 == 'hello world_2', + }); + + jar.delete('https://httpbin.test.k6.io/cookies', 'my_cookie_1'); + + const res2 = http.get('https://httpbin.test.k6.io/cookies'); + check(res2, { + 'res2 has status 200': (r) => r.status === 200, + "res2 doesn't have cookie 'my_cookie_1'": (r) => r.json().cookies.my_cookie_1 == null, + "res2 has cookie 'my_cookie_2'": (r) => r.json().cookies.my_cookie_2 !== null, + 'res2 cookie has correct value_2': (r) => r.json().cookies.my_cookie_2 == 'hello world_2', + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-set-url-name-value-options.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-set-url-name-value-options.md new file mode 100644 index 0000000000..57e976f935 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60 CookieJar/CookieJar-set-url-name-value-options.md @@ -0,0 +1,41 @@ +--- +title: 'CookieJar.set(url, name, value, [options])' +excerpt: 'Set a cookie in the jar by specifying url, name, value and some other optional settings like domain, path, etc.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/cookiejar/cookiejar-set/ +--- + +Set a cookie in the jar by specifying url, name, value and some other optional settings like domain, path, etc. + +| Parameter | Type | Description | +| ------------------ | ------ | ------------------------------------------------------------------------------------------- | +| url | string | Cookie URL | +| name | string | Cookie name | +| value | string | Cookie value | +| options (optional) | object | Specific cookie settings: `domain`, `path`, `expires`, `max_age`, `secure` and `http_only`. | + +### Example + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const jar = http.cookieJar(); + jar.set('https://httpbin.test.k6.io/cookies', 'my_cookie', 'hello world', { + domain: 'httpbin.test.k6.io', + path: '/cookies', + secure: true, + max_age: 600, + }); + const res = http.get('https://httpbin.test.k6.io/cookies'); + check(res, { + 'has status 200': (r) => r.status === 200, + "has cookie 'my_cookie'": (r) => r.json().cookies.my_cookie !== null, + 'cookie has correct value': (r) => r.json().cookies.my_cookie == 'hello world', + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60-FileData.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60-FileData.md new file mode 100644 index 0000000000..e747a25acd --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60-FileData.md @@ -0,0 +1,37 @@ +--- +title: 'FileData' +description: 'Used for wrapping data representing a file when doing multipart requests (file uploads).' +excerpt: 'Used for wrapping data representing a file when doing multipart requests (file uploads).' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/filedata/ +--- + +_FileData_ is an object for wrapping data representing a file when doing +[multipart requests (file uploads)](/examples/data-uploads#multipart-request-uploading-a-file). +You create it by calling [http.file( data, [filename], [contentType] )](/javascript-api/k6-http/file). + +| Name | Type | Description | +| --------------------- | ---------------------------- | ------------------------------------------------------------------------ | +| FileData.data | string / Array / ArrayBuffer | File data as string, array of numbers, or an `ArrayBuffer` object. | +| FileData.content_type | string | The content type that will be specified in the multipart request. | +| FileData.filename | string | The filename that will be specified in the multipart request. | + +### Example + + + +```javascript +import { sleep } from 'k6'; +import { md5 } from 'k6/crypto'; +import http from 'k6/http'; + +const binFile = open('/path/to/file.bin', 'b'); + +export default function () { + const f = http.file(binFile, 'test.bin'); + console.log(md5(f.data, 'hex')); + console.log(f.filename); + console.log(f.content_type); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/60-Params.md b/src/data/markdown/docs/02 javascript api/09 k6-http/60-Params.md new file mode 100644 index 0000000000..aff01e66e8 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/60-Params.md @@ -0,0 +1,122 @@ +--- +title: 'Params' +description: 'Used for setting various HTTP request-specific parameters such as headers, cookies, etc.' +excerpt: 'Used for setting various HTTP request-specific parameters such as headers, cookies, etc.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/params/ +--- + +_Params_ is an object used by the http.\* methods that generate HTTP requests. _Params_ contains request-specific options like e.g. HTTP headers that should be inserted into the request. + +| Name | Type | Description | +| --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Params.auth` | string | The authentication method used for the request. It currently supports `digest`, `ntlm`, and `basic` authentication methods. | +| `Params.cookies` | object | Object with key-value pairs representing request scoped cookies (they won't be added to VU cookie jar)
`{cookies: { key: "val", key2: "val2" }}`

You also have the option to say that a request scoped cookie should override a cookie in the VU cookie jar:
`{cookies: { key: { value: "val", replace: true }}}` | +| `Params.headers` | object | Object with key-value pairs representing custom HTTP headers the user would like to add to the request. | +| `Params.jar` | object | http.CookieJar object to override default VU cookie jar with. Cookies added to request will be sourced from this jar and cookies set by server will be added to this jar. | +| `Params.redirects` | number | The number of redirects to follow for this request. Overrides the global test option [`maxRedirects`](/using-k6/k6-options/reference). | +| `Params.tags` | object | Key-value pairs where the keys are names of tags and the values are tag values. Response time metrics generated as a result of the request will have these tags added to them, allowing the user to filter out those results specifically, when looking at results data. | +| `Params.timeout` | string / number | Maximum time to wait for the request to complete. Default timeout is 60 seconds (`"60s"`).
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | +| `Params.compression` | string | Sets whether the request body should be compressed. If set to `gzip` it will use gzip to compress the body and set the appropriate `Content-Length` and `Content-Encoding` headers.

Possible values: `gzip`, `deflate`, `br`, `zstd`, and any comma-separated combination of them (for stacked compression) | +| `Params.responseType` | string | ResponseType is used to specify how to treat the body of the response. The three options are:
- text: k6 will return it as a string. This might not be what you want in cases of binary data as the conversation to UTF-16 will probably break it. This is also the default if
[discardResponseBodies](/using-k6/k6-options/reference) is set to false or not set at all.
- `binary`: k6 will return an ArrayBuffer object
- `none`: k6 will return null as the body. The whole body will be ignored. This is the default when [discardResponseBodies](/using-k6/k6-options/reference) is set to true. | +| `Params.responseCallback` | [expectedStatuses](/javascript-api/k6-http/expectedstatuses) | sets a [responseCallback](/javascript-api/k6-http/setresponsecallback) only for this request. For performance reasons it's better to initialize it once and reference it for each time the same callback will need to be used| + +### Example of custom HTTP headers and tags + +_A k6 script that will make an HTTP request with a custom HTTP header and tag results data with a specific tag_ + + + +```javascript +import http from 'k6/http'; + +export default function () { + const params = { + cookies: { my_cookie: 'value' }, + headers: { 'X-MyHeader': 'k6test' }, + redirects: 5, + tags: { k6test: 'yes' }, + }; + const res = http.get('https://k6.io', params); +} +``` + + + +### Example using http.batch() with Params + +Here is another example using [http.batch()](/javascript-api/k6-http/batch) with a `Params` argument: + + + +```javascript +import http from 'k6/http'; + +const url1 = 'https://api.k6.io/v3/account/me'; +const url2 = 'https://httpbin.test.k6.io/get'; +const apiToken = 'f232831bda15dd233c53b9c548732c0197619a3d3c451134d9abded7eb5bb195'; +const requestHeaders = { + 'User-Agent': 'k6', + 'Authorization': 'Token ' + apiToken, +}; + +export default function () { + const res = http.batch([ + { method: 'GET', url: url1, params: { headers: requestHeaders } }, + { method: 'GET', url: url2 }, + ]); +} +``` + + + +### Example of Digest Authentication + +Here is one example of how to use the `Params` to Digest Authentication. + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + // Passing username and password as part of URL plus the auth option will authenticate using HTTP Digest authentication + const res = http.get('http://user:passwd@httpbin.test.k6.io/digest-auth/auth/user/passwd', { + auth: 'digest', + }); + + // Verify response + check(res, { + 'status is 200': (r) => r.status === 200, + 'is authenticated': (r) => r.json().authenticated === true, + 'is correct user': (r) => r.json().user === 'user', + }); +} +``` + + + +### Example of overriding discardResponseBodies + + + +```javascript +import http from 'k6/http'; + +export const options = { discardResponseBodies: true }; +export default function () {} +export function setup() { + // Get 10 random bytes as an ArrayBuffer. Without the responseType the body + // will be null. + const response = http.get('https://httpbin.test.k6.io/bytes/10', { + responseType: 'binary', + }); + // response.body is an ArrayBuffer, so wrap it in a typed array view to access + // its elements. + const bodyView = new Uint8Array(response.body); + // This will output something like `176,61,15,66,233,98,223,196,43,1` + console.log(bodyView); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response.md b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response.md new file mode 100644 index 0000000000..23f5e60be0 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response.md @@ -0,0 +1,76 @@ +--- +title: 'Response' +description: 'Returned by the http.* methods that generate HTTP requests.' +excerpt: 'Returned by the http.* methods that generate HTTP requests.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/response/ +--- + +Response is used by the http.\* methods that generate HTTP request. Those methods return one (or more, in the case of `http.batch()`) Response objects that contain HTTP response contents and performance timing measurements. + +Note that in the case of redirects, all the information in the Response object will pertain to the last request (the one that doesn't get redirected). + +| Name | Type | Description | +| ---------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Response.body` | string | Response body content, often used to extract dynamic data (see examples [here](/examples/correlation-and-dynamic-data)) and when verifying the presence of content using [checks](/javascript-api/k6/check).

See [Params.responseType](/javascript-api/k6-http/params) and [options.discardResponseBodies](/using-k6/k6-options/reference) for how to discard the body when it is not needed (and to save memory) or when handling bodies with binary data. | +| `Response.cookies` | object | Response cookies. The object properties are the cookie names and the value is an array of cookie objects (with `name`, `value`, `domain`, `path`, `httpOnly`, `secure`, `maxAge` and `expires` fields). | +| `Response.error` | string | Error message if there was a non-HTTP error while trying to send the request. | +| `Response.error_code` | number | [Error code](/javascript-api/error-codes) if there was a non-HTTP error or 4xx or 5xx HTTP error it will be set to a specific code that describes the error. (Added in 0.24.0) | +| `Response.headers` | object | Key-value pairs representing all HTTP headers sent by the server. Note that the header names are in [canonical form](https://pkg.go.dev/net/http#CanonicalHeaderKey), i.e.: if the server responds with "accept-encoding", the key will be "Accept-Encoding". | +| `Response.ocsp.produced_at` | number | If a stapled OSCP response was provided by server, the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when this OCSP stapled response was signed by CA (or by CA entrusted OCSP responder) | +| `Response.ocsp.this_update` | number | If a stapled OSCP response was provided by server, the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time at which the status being indicated was known to be correct. | +| `Response.ocsp.next_update` | number | If a stapled OSCP response was provided by server, the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when this OCSP stapled response will be refreshed with CA (or by CA entrusted OCSP responder). | +| `Response.ocsp.revocation_reason` | string | The reason for revocation of the certificate (if that is the status), one of the following constants: `http.OCSP_REASON_UNSPECIFIED`, `http.OCSP_REASON_KEY_COMPROMISE`, `http.OCSP_REASON_CA_COMPROMISE`,
`http.OCSP_REASON_AFFILIATION_CHANGED`,
`http.OCSP_REASON_SUPERSEDED`,
`http.OCSP_REASON_CESSATION_OF_OPERATION`,
`http.OCSP_REASON_CERTIFICATE_HOLD`,
`http.OCSP_REASON_REMOVE_FROM_CRL`,
`http.OCSP_REASON_PRIVILEGE_WITHDRAWN` or
`http.OCSP_REASON_AA_COMPROMISE`. | +| `Response.ocsp.revoked_at` | number | If a stapled OSCP response was provided by server, the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when this certificate was revoked (if that is the status). | +| `Response.ocsp.status` | string | The status of the certificate, one of the following constants: `http.OCSP_STATUS_GOOD`, `http.OCSP_STATUS_REVOKED`, `http.OCSP_STATUS_UNKNOWN` or `http.OCSP_STATUS_SERVER_FAILED`. | +| `Response.proto` | string | Protocol used to perform the transfer. Possible values are "HTTP/1.0", "HTTP/1.1", or "HTTP/2.0". | +| `Response.remote_ip` | string | The IP address of the server handling the request. | +| `Response.remote_port` | number | The port that was connected to on the server side. | +| `Response.request.body` | string | Request body content. | +| `Response.request.cookies` | object | Request cookies. The object properties are the cookie names and the value is an array of cookie objects (with `name`, `value` and `replace` fields). | +| `Response.request.headers` | object | Request headers. | +| `Response.request.method` | string | Request HTTP method. | +| `Response.request.url` | string | Request URL. | +| `Response.status` | number | HTTP status code returned by the server. | +| `Response.status_text` | string | _(new in k6 v0.29.0)_ HTTP status text returned by the server. | +| `Response.timings` | object | Performance timing information for the HTTP request. | +| `Response.timings.blocked` | float | Containing time (ms) spent blocked before initiating request. | +| `Response.timings.connecting` | float | Containing time (ms) spent setting up TCP connection to host. | +| `Response.timings.tls_handshaking` | float | Containing time (ms) spent handshaking TLS session with host. | +| `Response.timings.sending` | float | Containing time (ms) spent sending request. | +| `Response.timings.waiting` | float | Containing time (ms) spent waiting for server response. | +| `Response.timings.receiving` | float | Containing time (ms) spent receiving response data. | +| `Response.timings.duration` | float | Total time for the request (ms). It's equal to `sending + waiting + receiving`, i.e. how long did the remote server take to process the request and respond, without the initial DNS lookup/connection times. | +| `Response.tls_cipher_suite` | string | If a TLS session was established, the cipher suite that was used. | +| `Response.tls_version` | string | If a TLS session was established, the version of SSL/TLS that was used. | +| `Response.url` | string | The URL that was ultimately fetched (i.e. after any potential redirects). | +| [Response.clickLink( [params] )](/javascript-api/k6-http/response/response-clicklink) | function | Parses response as HTML, looks for a specific link and does the request-level equivalent of a click on that link. | +| [Response.html()](/javascript-api/k6-http/response/response-html) | function | Returns an object that supports [Selection.find(selector)](/javascript-api/k6-html/selection/selection-find). | +| [Response.json( [selector] )](/javascript-api/k6-http/response/response-json) | function | Parses the response body data as JSON and returns a JS object or array. This call caches the deserialized JSON data, additional calls will return the cached data. An optional selector can be specified to extract a specific part of the data, see [here for selector syntax](https://github.com/tidwall/gjson#path-syntax). | +| [Response.submitForm( [params] )](/javascript-api/k6-http/response/response-submitform) | function | Parses response as HTML, parses the specified form (defaults to looking for a "form" element) with option to override fields and then submits form taking form's `method` and `action` into account. | + +### Example + + + +```javascript +import { check } from 'k6'; +import http from 'k6/http'; + +export default function () { + const res = http.get('https://k6.io'); + for (const p in res.headers) { + if (res.headers.hasOwnProperty(p)) { + console.log(p + ' : ' + res.headers[p]); + } + } + check(res, { + 'status is 200': (r) => r.status === 200, + 'caption is correct': (r) => r.html('h1').text() == 'Example Domain', + }); +} +``` + + + +_A k6 script that will make an HTTP request and print all HTTP response headers_ + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-clickLink- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-clickLink- -params- -.md new file mode 100644 index 0000000000..49b63131ff --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-clickLink- -params- -.md @@ -0,0 +1,38 @@ +--- +title: 'Response.clickLink( [params] )' +excerpt: 'Create and make a request corresponding to a link, found in the HTML of response, being clicked.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/response/response-clicklink/ +--- + +Create and make a request corresponding to a link, found in the HTML of response, being clicked. By default it will look for the first `a` tag with a `href` attribute in the HTML, but this can be overridden using the `selector` option. + +This method takes an object argument where the following properties can be set: + +| Param | Type | Description | +| -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| selector | string | A selector string passed to [Selection.find(selector)](/javascript-api/k6-html/selection/selection-find) to locate the link to click. By default this is `"a[href]"`. | +| params | object | A [Params](/javascript-api/k6-http/params) object that will be forwarded to the link click request. Can be used to set headers, cookies etc. | + +### Returns + +| Type | Description | +| -------------------------------------------- | ----------------------- | +| [Response](/javascript-api/k6-http/response) | The link click response | + +### Example + + + +```javascript +import http from 'k6/http'; + +export default function () { + // Request page with links + let res = http.get('https://httpbin.test.k6.io/links/10/0'); + + // Now, click the 4th link on the page + res = res.clickLink({ selector: 'a:nth-child(4)' }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-html--.md b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-html--.md new file mode 100644 index 0000000000..07080fae00 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-html--.md @@ -0,0 +1,35 @@ +--- +title: 'Response.html()' +excerpt: 'Parses response as HTML and populate a Selection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/response/response-html/ +--- + +Parses response as HTML and populate a [Selection](/javascript-api/k6-html/selection) object. + +### Returns + +| Type | Description | +| ---------------------------------------------- | ------------------ | +| [Selection](/javascript-api/k6-html/selection) | A Selection object | + +### Example + + + +```javascript +import http from 'k6/http'; + +export default function () { + const res = http.get('https://stackoverflow.com'); + + const doc = res.html(); + doc + .find('link') + .toArray() + .forEach(function (item) { + console.log(item.attr('href')); + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-json- -selector- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-json- -selector- -.md new file mode 100644 index 0000000000..3a772cc238 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-json- -selector- -.md @@ -0,0 +1,35 @@ +--- +title: 'Response.json( [selector] )' +excerpt: 'Parses the response body data as JSON and returns a JS object or array.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/response/response-json/ +--- + +Parses the response body data as JSON and returns a JS object or array. This call caches the deserialized JSON data, additional calls will return the cached data. An optional selector can be specified to extract a specific part of the data, see [here for selector syntax](https://github.com/tidwall/gjson#path-syntax). + +This method takes an object argument where the following properties can be set: + +| Param | Type | Description | +| -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| selector | string | An optional selector can be specified to extract a specific part of the data, see [here for selector syntax](https://github.com/tidwall/gjson#path-syntax). | + +### Returns + +| Type | Description | +| --------------- | ----------------------------------------- | +| Object or array | Returns the response body as JSON object. | + +### Example + + + +```javascript +import http from 'k6/http'; + +export default function () { + const res = http.get('https://test-api.k6.io/public/crocodiles/'); + + console.log(res.json()); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-submitForm- -params- -.md b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-submitForm- -params- -.md new file mode 100644 index 0000000000..8a618b147e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/09 k6-http/61 Response/Response-submitForm- -params- -.md @@ -0,0 +1,45 @@ +--- +title: 'Response.submitForm( [params] )' +excerpt: 'Fill in and submit form found in HTML of response.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-http/response/response-submitform/ +--- + +Fill in and submit form found in HTML of response. By default it will look for the first `form` tag in the HTML, but this can be overridden using the `formSelector` option. To set/override the form fields you set properties of an object in the `fields` option. + +This method takes an object argument where the following properties can be set: + +| Param | Type | Description | +| -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| formSelector | string | A selector string passed to [Selection.find(selector)](/javascript-api/k6-html/selection/selection-find) to locate the form to fill in and submit. By default this is `"form"`. | +| fields | object | The form fields to set/override. The keys are the form fields names and the values are the form field values. | +| submitSelector | string | A selector string used to locate the submit button in the form. By default this is `'[type="submit"]'`. | +| params | object | A [Params (k6/http)](/javascript-api/k6-http/params) object that will be forwarded to the form submit request. Can be used to set headers, cookies etc. | + +### Returns + +| Type | Description | +| ------------------------------------------------------ | ------------------------- | +| [Response (k6/http)](/javascript-api/k6-http/response) | The form submit response. | + +### Example + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +export default function () { + // Request page containing a form + let res = http.get('https://httpbin.test.k6.io/forms/post'); + + // Now, submit form setting/overriding some fields of the form + res = res.submitForm({ + formSelector: 'form', + fields: { custname: 'test', extradata: 'test2' }, + }); + sleep(3); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics.md index 112f5c2d0f..b76ff74c92 100644 --- a/src/data/markdown/docs/02 javascript api/10 k6-metrics.md +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics.md @@ -2,7 +2,16 @@ title: 'k6/metrics' excerpt: 'k6 Custom Metrics API' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/ --- -The metrics module provides functionality to create custom metrics of various types. \ No newline at end of file +The metrics module provides functionality to [create custom metrics](/using-k6/metrics/create-custom-metrics) of various types. +All metrics (both the [built-in metrics](/using-k6/metrics/reference) and the custom ones) have a type. + +You can optionally [tag](/using-k6/tags-and-groups) all values added to a custom metric, which can be useful when analysing the test results. + +| Metric type | Description | +| --------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| [Counter](/javascript-api/k6-metrics/counter) | A metric that cumulatively sums added values. | +| [Gauge](/javascript-api/k6-metrics/gauge) | A metric that stores the min, max and last values added to it. | +| [Rate](/javascript-api/k6-metrics/rate) | A metric that tracks the percentage of added values that are non-zero. | +| [Trend](/javascript-api/k6-metrics/trend) | A metric that calculates statistics on the added values (min, max, average, and percentiles). | diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/70 Counter.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/70 Counter.md new file mode 100644 index 0000000000..b137fdfa99 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/70 Counter.md @@ -0,0 +1,103 @@ +--- +title: 'Counter' +excerpt: 'Counter is an object for representing a custom cumulative counter metric. It is one of the four custom metric types.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/counter/ +--- + +_Counter_ is an object for representing a custom cumulative counter metric. It is one of the four custom metric types. + +| Parameter | Type | Description | +| --------- | ------ | ------------------------------ | +| `name` | string | The name of the custom metric. | + +| Method | Description | +| --------------------------------------------------------------------------------------- | ---------------------------------- | +| [Counter.add(value, [tags])](/javascript-api/k6-metrics/counter/counter-add) | Add a value to the counter metric. | + +## Counter usage in Thresholds + +When `Counter` is used in a threshold expression, the variable must be called `count` or `rate` (lower case). +For example: + +- `count >= 200` // value of the counter must be larger or equal to 200 +- `count < 10` // less than 10. + +### Examples + + + +```javascript +import { Counter } from 'k6/metrics'; + +const myCounter = new Counter('my_counter'); + +export default function () { + myCounter.add(1); + myCounter.add(2, { tag1: 'myValue', tag2: 'myValue2' }); +} +``` + + + + + +```javascript +import http from 'k6/http'; +import { Counter } from 'k6/metrics'; + +const CounterErrors = new Counter('Errors'); + +export const options = { thresholds: { Errors: ['count<100'] } }; + +export default function () { + const res = http.get('https://test-api.k6.io/public/crocodiles/1/'); + const contentOK = res.json('name') === 'Bert'; + CounterErrors.add(!contentOK); +} +``` + + + + + +```javascript +import { Counter } from 'k6/metrics'; +import { sleep } from 'k6'; +import http from 'k6/http'; + +const allErrors = new Counter('error_counter'); + +export const options = { + vus: 1, + duration: '1m', + thresholds: { + 'error_counter': [ + 'count < 10', // 10 or fewer total errors are tolerated + ], + 'error_counter{errorType:authError}': [ + // Threshold on a sub-metric (tagged values) + 'count <= 2', // max 2 authentication errors are tolerated + ], + }, +}; + +export default function () { + const auth_resp = http.post('https://test-api.k6.io/auth/token/login/', { + username: 'test-user', + password: 'supersecure', + }); + + if (auth_resp.status >= 400) { + allErrors.add(1, { errorType: 'authError' }); // tagged value creates submetric (useful for making thresholds specific) + } + + const other_resp = http.get('https://test-api.k6.io/public/crocodiles/1/'); + if (other_resp.status >= 400) { + allErrors.add(1); // untagged value + } + + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/70 Counter/Counter-add-value- -tags--.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/70 Counter/Counter-add-value- -tags--.md new file mode 100644 index 0000000000..fc55b0d55d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/70 Counter/Counter-add-value- -tags--.md @@ -0,0 +1,15 @@ +--- +title: "Counter.add(value, [tags])" +excerpt: 'Add a value to the Counter metric.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/counter/counter-add/ +--- + +Add a value to the `Counter` metric. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| value | number | The value to add to the counter. | +| tags | object | Set of [tags](/using-k6/tags-and-groups) that will be tagged to the added data point (note that tags are added per data point and not for the entire metric). | + + +[Counter examples](/javascript-api/k6-metrics/counter#examples) diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/71 Gauge.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/71 Gauge.md new file mode 100644 index 0000000000..ce44f8d8c2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/71 Gauge.md @@ -0,0 +1,66 @@ +--- +title: 'Gauge' +excerpt: 'Gauge is an object for representing a custom metric holding only the latest value added.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/gauge/ +--- + +_Gauge_ is an object for representing a custom metric holding only the latest value added. It is one of the four [custom metrics](/javascript-api/k6-metrics). + +| Parameter | Type | Description | +| --------- | ------- | --------------------------------------------------------------------------------------------------- | +| `name` | string | The name of the custom metric. | +| `isTime` | boolean | A boolean indicating whether the values added to the metric are time values or just untyped values. | + +| Method | Description | +| --------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | +| [Gauge.add(value, [tags])](/javascript-api/k6-metrics/gauge/gauge-add) | Add a value to the gauge metric. Only the latest value added will be kept. | + +## Gauge usage in Thresholds + +When gauge is used in a threshold expression, the variable must be called `value` (lower case). +For example: + +- `value < 200` +- `value > 1` + +### Examples + + + +```javascript +import { Gauge } from 'k6/metrics'; + +const myGauge = new Gauge('my_gauge'); + +export default function () { + myGauge.add(3); + myGauge.add(1); + myGauge.add(2, { tag1: 'value', tag2: 'value2' }); +} +``` + + + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; +import { Gauge } from 'k6/metrics'; + +const GaugeContentSize = new Gauge('ContentSize'); + +export const options = { + thresholds: { + ContentSize: ['value<4000'], + }, +}; + +export default function () { + const res = http.get('https://test-api.k6.io/public/crocodiles/1/'); + GaugeContentSize.add(res.body.length); + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/71 Gauge/Gauge-add-value- -tags--.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/71 Gauge/Gauge-add-value- -tags--.md new file mode 100644 index 0000000000..06fafede93 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/71 Gauge/Gauge-add-value- -tags--.md @@ -0,0 +1,14 @@ +--- +title: "Gauge.add(value, [tags])" +excerpt: 'Set the value of the Gauge metric.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/gauge/gauge-add/ +--- + +Set the value of the `Gauge` metric. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| value | number | The value to set the gauge to. | +| tags | object | Set of [tags](/using-k6/tags-and-groups) that will be tagged to the added data point (note that tags are added per data point and not for the entire metric). | + +[Gauge examples](/javascript-api/k6-metrics/gauge#examples) diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/72 Rate.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/72 Rate.md new file mode 100644 index 0000000000..68ba194651 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/72 Rate.md @@ -0,0 +1,75 @@ +--- +title: 'Rate' +excerpt: 'Rate is an object for representing a custom metric keeping track of the percentage of added values that are non-zero.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/rate/ +--- + +_Rate_ is an object for representing a custom metric keeping track of the percentage of added values that are non-zero. It is one of the four [custom metrics](/javascript-api/k6-metrics). + +| Parameter | Type | Description | +| --------- | ------ | ------------------------------ | +| `name` | string | The name of the custom metric. | + +| Method | Description | +| -------------------------------------------------------------------------------- | ------------------------------- | +| [Rate.add(value, [tags])](/javascript-api/k6-metrics/rate/rate-add) ] | Add a value to the rate metric. | + +## Rate usage in Thresholds + +When `Rate` is used in a threshold expression, the variable must be called `rate` (lower case). +For example: + +- `rate < 0.1` // less than 10% +- `rate >= 0.9` // more or equal to 90% + +The value of the `rate` variable ranges between `0.00` and `1.00`. + +### Examples + + + +```javascript +import { Rate } from 'k6/metrics'; + +const myRate = new Rate('my_rate'); + +export default function () { + myRate.add(true); + myRate.add(false); + myRate.add(1); + myRate.add(0, { tag1: 'value', tag2: 'value2' }); +} +``` + + + + + +```javascript +import { Rate } from 'k6/metrics'; +import { sleep } from 'k6'; +import http from 'k6/http'; + +const errorRate = new Rate('errorRate'); + +export const options = { + vus: 1, + duration: '5m', + thresholds: { + errorRate: [ + // more than 10% of errors will abort the test + { threshold: 'rate < 0.1', abortOnFail: true, delayAbortEval: '1m' }, + ], + }, +}; + +export default function () { + const resp = http.get('https://test-api.k6.io/public/crocodiles/1/'); + + errorRate.add(resp.status >= 400); + + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/72 Rate/Rate-add-value- -tags--.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/72 Rate/Rate-add-value- -tags--.md new file mode 100644 index 0000000000..654d6bca84 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/72 Rate/Rate-add-value- -tags--.md @@ -0,0 +1,14 @@ +--- +title: "Rate.add(value, [tags])" +excerpt: 'Set the value of the Rate metric.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/rate/rate-add/ +--- + +Set the value of the `Rate` metric. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| value | number | The value to add to the rate metric. | +| tags | object | Set of [tags](/using-k6/tags-and-groups) that will be tagged to the added data point (note that tags are added per data point and not for the entire metric). | + +[Rate examples](/javascript-api/k6-metrics/rate#examples) diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/73 Trend.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/73 Trend.md new file mode 100644 index 0000000000..9b88dbb330 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/73 Trend.md @@ -0,0 +1,88 @@ +--- +title: 'Trend' +excerpt: 'Trend is an object for representing a custom metric that allows for calculating different statistics on the added values (min, max, average or percentiles)' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/trend/ +--- + +_Trend_ is an object for representing a custom metric that allows for calculating different statistics on the added values (min, max, average or percentiles). It is one of the four [custom metrics](/javascript-api/k6-metrics). + +| Parameter | Type | Description | +| --------- | ------- | --------------------------------------------------------------------------------------------------- | +| `name` | string | The name of the custom metric. | +| `isTime` | boolean | A boolean indicating whether the values added to the metric are time values or just untyped values. | + +| Method | Description | +| --------------------------------------------------------------------------------- | -------------------------------- | +| [Trend.add(value, [tags])](/javascript-api/k6-metrics/trend/trend-add) | Add a value to the trend metric. | + +## Trend usage in Thresholds + +When `Trend` is used in a [threshold expression](/using-k6/thresholds), there are a range of variables that can be used. + +- `avg` for average +- `min` for minimum +- `max` for maximum +- `med` for median +- `p(N)` for specific percentile. `N` is a number between `0.0` and `100.0` meaning the percentile value to look at, e.g. `p(99.99)` means the 99.99th percentile. + +The unit of these variables and functions are all in milliseconds. + +### Example threshold expressions: + +- `p(95) < 400` // 95% of requests must finish below 400ms +- `p(99) < 1000` // 99% of requests must finish within 1s. +- `p(50) < 200` // half of requests must finish within 200ms. +- `max < 3000` // the slowest request must finish within 3s. + + +> #### ⚠️ Don't use `min` and `max` in thresholds +> We don't recommend using `min` and `max` for specifying thresholds because these +> values represent outliers. Use percentiles instead. + + +### Examples + + + +```javascript +import { Trend } from 'k6/metrics'; + +const myTrend = new Trend('my_trend'); + +export default function () { + myTrend.add(1); + myTrend.add(2, { tag1: 'value', tag2: 'value2' }); +} +``` + + + + + +```javascript +import { Trend } from 'k6/metrics'; +import { sleep } from 'k6'; +import http from 'k6/http'; + +const serverWaitingTimeOnLogin = new Trend('serverWaitingTimeOnLogin', true); + +export const options = { + vus: 1, + duration: '1m', + thresholds: { + serverWaitingTimeOnLogin: ['p(95) < 200'], + }, +}; + +export default function () { + const resp = http.post('https://test-api.k6.io/auth/token/login/', { + username: 'test-user', + password: 'supersecure', + }); + + serverWaitingTimeOnLogin.add(resp.timings.waiting); + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/10 k6-metrics/73 Trend/Trend-add-value- -tags--.md b/src/data/markdown/docs/02 javascript api/10 k6-metrics/73 Trend/Trend-add-value- -tags--.md new file mode 100644 index 0000000000..5092ed607c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/10 k6-metrics/73 Trend/Trend-add-value- -tags--.md @@ -0,0 +1,15 @@ +--- +title: "Trend.add(value, [tags])" +excerpt: 'Add a value to the Trend metric.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-metrics/trend/trend-add/ +--- + +Add a value to the `Trend` metric. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| value | number | The value to add to the trend metric. | +| tags | object | Set of [tags](/using-k6/tags-and-groups) that will be tagged to the added data point (note that tags are added per data point and not for the entire metric). | + + +[Trend examples](/javascript-api/k6-metrics/trend#examples) \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md index aaa1b6d612..6cf2944698 100644 --- a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc.md @@ -2,9 +2,57 @@ title: "k6/net/grpc" excerpt: "k6 gRPC API" canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/ --- + The `k6/net/grpc` module provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2. + +| Class/Method | Description | +|--------------|-------------| +| [Client](/javascript-api/k6-net-grpc/client) | gRPC client used for making RPC calls to a gRPC Server. | +| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-net-grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. | +| [Client.connect(address [,params])](/javascript-api/k6-net-grpc/client/client-connect) | Connects to a given gRPC service. | +| [Client.invoke(url, request [,params])](/javascript-api/k6-net-grpc/client/client-invoke) | Makes an unary RPC for the given service/method and returns a [Response](/javascript-api/k6-net-grpc/response). | +| [Client.close()](/javascript-api/k6-net-grpc/client/client-close) | Close the connection to the gRPC service. | +| [Params](/javascript-api/k6-net-grpc/params) | RPC Request specific options. | +| [Response](/javascript-api/k6-net-grpc/response) | Returned by RPC requests. | +| [Constants](/javascript-api/k6-net-grpc/constants) | Define constants to distinguish between [gRPC Response](/javascript-api/k6-net-grpc/response) statuses. | + +## gRPC metrics + +k6 takes specific measurements for gRPC requests. +For the complete list, refer to the [Metrics reference](/using-k6/metrics/reference#grpc). + +### Example + + + +```javascript +import grpc from 'k6/net/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/10-Client.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/10-Client.md new file mode 100644 index 0000000000..caacb1e747 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/10-Client.md @@ -0,0 +1,107 @@ +--- +title: Client +excerpt: 'Client is a gRPC client that can interact with a gRPC server.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/ +--- + + + +`Client` is a gRPC client that can interact with a gRPC server. Only unary RPCs are currently supported in this module. + + +| Method | Description | +|--------|-------------| +| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-net-grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. | +| [Client.loadProtoset(protosetPath)](/javascript-api/k6-net-grpc/client/client-loadprotoset) | Loads and parses the given protoset file to be made available for RPC requests. | +| [Client.connect(address [,params])](/javascript-api/k6-net-grpc/client/client-connect) | Opens a connection to the given gRPC server. | +| [Client.invoke(url, request [,params])](/javascript-api/k6-net-grpc/client/client-invoke) | Makes an unary RPC for the given service/method and returns a [Response](/javascript-api/k6-net-grpc/response). | +| [Client.close()](/javascript-api/k6-net-grpc/client/client-close) | Close the connection to the gRPC service. | + + +### Examples + +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); +// Download addsvc.proto for https://grpcbin.test.k6.io/, located at: +// https://raw.githubusercontent.com/moul/pb/master/addsvc/addsvc.proto +// and put it in the same folder as this script. +client.load(null, 'addsvc.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { timeout: '5s' }); + + const response = client.invoke('addsvc.Add/Sum', { + a: 1, + b: 2, + }); + console.log(response.message.v); // should print 3 + + client.close(); +}; +``` + +
+ +
+ +```javascript +import grpc from 'k6/net/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'authorization.proto', 'route_guide.proto'); + +export function setup() { + client.connect('auth.googleapis.com:443'); + const resp = client.invoke('google.cloud.authorization.v1.AuthService/GetAccessToken', { + username: 'john.smith@k6.io', + password: 'its-a-secret', + }); + client.close(); + return resp.message.accessToken; +} + +export default (token) => { + client.connect('route.googleapis.com:443'); + const metadata = { + authorization: `bearer ${token}`, + }; + const response = client.invoke( + 'google.cloud.route.v1.RoutingService/GetFeature', + { + latitude: 410248224, + longitude: -747127767, + }, + { metadata } + ); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + client.close(); +}; +``` + +
+ +
+ +```javascript +import grpc from 'k6/net/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'language_service.proto'); + +export default () => { + if (__ITER == 0) { + client.connect('language.googleapis.com:443'); + } + const response = client.invoke('google.cloud.language.v1.LanguageService/AnalyzeSentiment', {}); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + // Do NOT close the client +}; +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md new file mode 100644 index 0000000000..7f96c1d14e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/10-Client-load-importpaths-protoFiles copy.md @@ -0,0 +1,44 @@ +--- +title: "Client.load(importPaths, ...protoFiles)" +excerpt: 'Loads and parses the protocol buffer descriptors so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/client-load/ +--- + +Loads and parses the protocol buffer descriptors so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema. + +Must be called within the [`init` phase](/using-k6/test-lifecycle). + +| Parameter | Type | Description | +|-----------|------|-------------| +| importPaths | Array<string> \| `null` | The paths used to search for dependencies that are referenced in import statements in proto source files. If no import paths are provided then "." (current directory) is assumed to be the only import path. | +| protoFiles | Array<string> | [Rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) for the list of proto files to load/parse. | + +### Examples + +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); +client.load([], 'language_service.proto'); +``` + +
+ +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); + +client.load( + ['../googleapis/google'], + 'spanner/admin/instance/v1/spanner_instance_admin.proto', + 'spanner/admin/instance/v1/spanner_instance_admin.proto', + 'spanner/v1/spanner.proto' +); +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/11-Client-load-protoset.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/11-Client-load-protoset.md new file mode 100644 index 0000000000..c609812232 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/11-Client-load-protoset.md @@ -0,0 +1,26 @@ +--- +title: "Client.loadProtoset(protosetPath)" +excerpt: 'Loads and parses the protoset file (serialized FileDescriptor set) so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/client-loadprotoset/ +--- + +Loads and parses the protoset file (serialized FileDescriptor set) so they are available to the client to marshal/unmarshal the correct request and response data structures for the RPC schema. + +Must be called within the [`init` phase](/using-k6/test-lifecycle). + +| Parameter | Type | Description | +|-----------|------|-------------| +| protosetPath | string | The path of the protoset file. If no import paths are provided then "." (current directory) is assumed to be the only import path. | + +### Examples + +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); +client.loadProtoset('./dummy.protoset'); +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md new file mode 100644 index 0000000000..d31e6501ed --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/20-Client-connect-connect-address-params.md @@ -0,0 +1,128 @@ +--- +title: "Client.connect(address [,params])" +excerpt: 'Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/client-connect/ +--- + +Opens a connection to a gRPC server; will block until a connection is made or a connection error is thrown. Cannot be called during the [`init` phase](/using-k6/test-lifecycle). + +See [Client.close()](/javascript-api/k6-net-grpc/client/client-close) to close the connection. + +| Parameter | Type | Description | +|-----------|------|-------------| +| address | string | The address of the gRPC server. Should be in the form: `host:port` with no protocol prefix e.g. `grpc.k6.io:443`. The host must be a literal IP address, or a host name that can be resolved to IP addresses. The port must be a literal port number or a service name e.g. `:443` or `:https`. If the host is a literal IPv6 address it must be enclosed in square brackets, as in `[2001:db8::1]:80` or `[fe80::1%zone]:80`. | +| params (optional) | object | [ConnectParams](#connectparams) object containing additional connect parameters. | + + +## ConnectParams + +| Name | Type | Description | +|------|------|-------------| +| `ConnectParams.plaintext` | bool | If `true` will connect to the gRPC server using plaintext i.e. insecure. Defaults to `false` i.e. secure via TLS. | +| `ConnectParams.reflect` | boolean | Whether to use the [gRPC server reflection protocol](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) when connecting. | +| `ConnectParams.reflectMetadata` | object | Object with key-value pairs representing custom metadata the user would like to add to the reflection request. | +| `ConnectParams.timeout` | string / number | Connection timeout to use. Default timeout is `"60s"`.
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | +| `ConnectParams.maxReceiveSize` | number | Sets the maximum message size in bytes the client can receive. Defaults to 0. | +| `ConnectParams.maxSendSize` | number | Sets the maximum message size in bytes the client can send. Defaults to 0. | +| `ConnectParams.tls` (optional) | object | [TLS](#tls) settings of the connection. Defaults to `null`. | + +## TLS + +TLS settings of the connection. If not defined, the main TLS config from options will be used. + +| Name | Type | Description | +|------|------|-------------| +| `tls.cert` | string | PEM formatted client certificate. | +| `tls.key` | string | PEM formatted client private key. | +| `tls.password` | string | Password for decrypting the client's private key. | +| `tls.cacerts` | string / array | PEM formatted strings of the certificate authorities. | + +### Examples + +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); + +export default () => { + client.connect('localhost:8080'); +}; +``` +
+ +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); + +export default () => { + client.connect('localhost:8080', { plaintext: true }); +}; +``` +
+ +
+ +```javascript +import grpc from "k6/experimental/grpc"; +import { check } from "k6"; +import { SharedArray } from "k6/data"; +import exec from "k6/execution"; + +// note: the services in this example don't exist. If you would like +// to run this example, make sure to replace the URLs, and +// the cacerts, cert, key, and password variables. +const grpcArgs = new SharedArray("grpc", () => { + // Using SharedArray here so that not every VU gets a copy of every certificate a key + return [ + { + host: "foo1.grpcbin.test.k6.io:9001", + plaintext: false, + params: { + tls: { + cacerts: [open("cacerts0.pem")], + cert: open("cert0.pem"), + key: open("key0.pem"), + }, + }, + }, + { + host: "foo2.grpcbin.test.k6.io:9002", + params: { + plaintext: false, + tls: { + cacerts: open("cacerts1.pem"), + cert: open("cert1.pem"), + key: open("key1.pem"), + password: "cert1-passphrase", + }, + }, + }, + ]; +}); + +const client = new grpc.Client(); + +export default () => { + if (__ITER === 0) { + // Take one config and use it for this one VU + const grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length]; + client.connect(grpcArg.host, grpcArg.params); + } + + const response = client.invoke("hello.HelloService/SayHello", { + greeting: "Bert", + }); + + check(response, { + "status is OK": (r) => r && r.status === grpc.StatusOK, + }); + + console.log(JSON.stringify(response.message)); +}; +``` +
\ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/30-Client-invokerpc-url-request-params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/30-Client-invokerpc-url-request-params.md new file mode 100644 index 0000000000..16e49734f2 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/30-Client-invokerpc-url-request-params.md @@ -0,0 +1,52 @@ +--- +title: "Client.invoke(url, request [,params])" +excerpt: 'Invokes an unary RPC request to the given method.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/client-invoke/ +--- + +Invokes an unary RPC request to the given method. + +The given method to invoke must have its RPC schema previously loaded via the [Client.load()](/javascript-api/k6-net-grpc/client/client-load) function, otherwise an +error will be thrown. + +[Client.connect()](/javascript-api/k6-net-grpc/client/client-connect) must be called first before invoking a request, otherwise an error will be thrown. + +| Parameter | Type | Description | +|-----------|------|-------------| +| url | string | The gRPC method url to invoke, in the form `/package.Service/Method`, e.g. `/google.cloud.language.v1.LanguageService/AnalyzeSentiment`. The leading slash `/` is optional. | +| request | object | The canonical request object, as-per the [Protobuf JSON Mapping](https://developers.google.com/protocol-buffers/docs/proto3#json). | +| params (optional) | object | [Params](/javascript-api/k6-net-grpc/params) object containing additional request parameters. + +### Returns + +| Type | Description | +|------|-------------| +| `Response` | gRPC [Response](/javascript-api/k6-net-grpc/response) object. | + +### Examples + +
+ +```javascript +import grpc from 'k6/net/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load([], 'routeguide.proto'); + +export default () => { + client.connect('localhost:10000', { plaintext: true }); + const response = client.invoke('main.RouteGuide/GetFeature', { + latitude: 410248224, + longitude: -747127767, + }); + check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK }); + console.log(response.message.name); + // output: 3 Hasta Way, Newton, NJ 07860, USA + + client.close(); +}; +``` + +
+ diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/40-Client-close.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/40-Client-close.md new file mode 100644 index 0000000000..0667e76099 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20 Client/40-Client-close.md @@ -0,0 +1,24 @@ +--- +title: "Client.close()" +excerpt: 'Close the connection to the gRPC service. Tear down all underlying connections.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/client-close/ +--- + +Close the connection to the gRPC service. Tear down all underlying connections. + +### Examples + +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('localhost:8080'); + client.close(); +}; +``` +
diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20-Params.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20-Params.md new file mode 100644 index 0000000000..d1f98718d4 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/20-Params.md @@ -0,0 +1,43 @@ +--- +title: "Params" +head_title: 'gRPC.params' +excerpt: 'Params is an object used by the gRPC methods that generate RPC requests.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/params/ +--- + +*Params* is an object used by the gRPC methods that generate RPC requests. *Params* contains request-specific options like headers that should be inserted into the request. + +| Name | Type | Description | +|------|------|-------------| +| `Params.metadata` | object | Object with key-value pairs representing custom metadata the user would like to add to the request. Values of [keys ending with `-bin`](https://grpc.io/docs/what-is-grpc/core-concepts/#metadata) will be treated as binary data. | +| `Params.tags` | object | Key-value pairs where the keys are names of tags and the values are tag values. Response time metrics generated as a result of the request will have these tags added to them, allowing the user to filter out those results specifically, when looking at results data. | +| `Params.timeout` | string / number | Request timeout to use. Default timeout is 60 seconds (`"60s"`).
The type can also be a number, in which case k6 interprets it as milliseconds, e.g., `60000` is equivalent to `"60s"`. | + + +### Example of custom metadata headers and tags + +
+ +```javascript +import grpc from 'k6/net/grpc'; + +const client = new grpc.Client(); +client.load([], 'route_guide.proto'); + +export default function () { + const req = { + latitude: 410248224, + longitude: -747127767, + }; + const params = { + metadata: { + 'x-my-header': 'k6test', + 'x-my-header-bin': new Uint8Array([1, 2, 3]), + }, + tags: { k6test: 'yes' }, + }; + const response = client.invoke('main.RouteGuide/GetFeature', req, params); +} +``` + +
diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/30-Response.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/30-Response.md new file mode 100644 index 0000000000..acb64ed98d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/30-Response.md @@ -0,0 +1,44 @@ +--- +title: "Response" +head_title: 'gRPC.Response' +excerpt: 'The response object of a gRPC request.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/response/ +--- + +| Name | Type | Description | +|------|------|-------------| +| `Response.status` | number | The response gRPC status code. Use the gRPC [status constants](/javascript-api/k6-net-grpc/constants) to check equality. | +| `Response.message` | object | The successful protobuf message, serialized to JSON. Will be `null` if `status !== grpc.StatusOK`. | +| `Response.headers` | object | Key-value pairs representing all the metadata headers returned by the gRPC server. | +| `Response.trailers` | object | Key-value pairs representing all the metadata trailers returned by the gRPC server. | +| `Response.error` | object | If `status !== grpc.StatusOK` then the error protobuf message, serialized to JSON; otherwise `null`. | + +### Example + + + +```javascript +import grpc from 'k6/net/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/40-Constants.md b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/40-Constants.md new file mode 100644 index 0000000000..91fe3e165e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/11 k6-net-grpc/40-Constants.md @@ -0,0 +1,57 @@ +--- +title: 'Constants' +excerpt: 'Define constants to distinguish between gRPC Response' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/constants/ +--- + +Define constants to distinguish between [gRPC Response](/javascript-api/k6-net-grpc/response) statuses. + +| Constant | Description | +|----------|-------------| +| `StatusOK` | OK is returned on success. | +| `StatusCanceled` | Canceled indicates the operation was canceled (typically by the caller). | +| `StatusUnknown` | Unknown error. | +| `StatusInvalidArgument` | InvalidArgument indicates the client specified an invalid argument. | +| `StatusDeadlineExceeded` | DeadlineExceeded means operation expired before completion. | +| `StatusNotFound` | NotFound means some requested entity (e.g., file or directory) was not found. | +| `StatusAlreadyExists` | AlreadyExists means an attempt to create an entity failed because one already exists. | +| `StatusPermissionDenied` | PermissionDenied indicates the caller does not have permission to execute the specified operation. | +| `StatusResourceExhausted` | ResourceExhausted indicates some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. | +| `StatusFailedPrecondition` | FailedPrecondition indicates operation was rejected because the system is not in a state required for the operation's execution. | +| `StatusAborted` | Aborted indicates the operation was aborted, typically due to a concurrency issue like sequencer check failures, transaction aborts, etc. | +| `StatusOutOfRange` | OutOfRange means operation was attempted past the valid range. E.g., seeking or reading past end of file. | +| `StatusUnimplemented` | Unimplemented indicates operation is not implemented or not supported/enabled in this service. | +| `StatusInternal` | Internal errors. Means some invariants expected by the underlying system have been broken. | +| `StatusUnavailable` | Unavailable indicates the service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. | +| `StatusDataLoss` | DataLoss indicates unrecoverable data loss or corruption. | +| `StatusUnauthenticated` | Unauthenticated indicates the request does not have valid authentication credentials for the operation. | + +### Example + + + +```javascript +import grpc from 'k6/net/grpc'; +import { check, sleep } from 'k6'; + +const client = new grpc.Client(); +client.load(['definitions'], 'hello.proto'); + +export default () => { + client.connect('grpcbin.test.k6.io:9001', { + // plaintext: false + }); + + const data = { greeting: 'Bert' }; + const response = client.invoke('hello.HelloService/SayHello', data); + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + + client.close(); + sleep(1); +}; +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws.md b/src/data/markdown/docs/02 javascript api/12 k6-ws.md index 3a2cca65d7..288894405d 100644 --- a/src/data/markdown/docs/02 javascript api/12 k6-ws.md +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws.md @@ -2,8 +2,28 @@ title: "k6/ws" excerpt: "k6 WebSocket API" canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/ --- + The ws module provides a [WebSocket](https://en.wikipedia.org/wiki/WebSocket) client implementing the [WebSocket protocol](http://www.rfc-editor.org/rfc/rfc6455.txt). + +| Function | Description | +| -------- | ----------- | +| [connect( url, params, callback )](/javascript-api/k6-ws/connect) | Create a WebSocket connection, and provides a [Socket](/javascript-api/k6-ws/socket) client to interact with the service. The method blocks the test finalization until the connection is closed. | + +| Class/Method | Description | +| ------------ | ----------- | +| [Params](/javascript-api/k6-ws/params/) | Used for setting various WebSocket connection parameters such as headers, cookie jar, compression, etc. | +| [Socket](/javascript-api/k6-ws/socket) | WebSocket client used to interact with a WS connection. | +| [Socket.close()](/javascript-api/k6-ws/socket/socket-close) | Close the WebSocket connection. | +| [Socket.on(event, callback)](/javascript-api/k6-ws/socket/socket-on) | Set up an event listener on the connection for any of the following events:
- open
- binaryMessage
- message
- ping
- pong
- close
- error. | +| [Socket.ping()](/javascript-api/k6-ws/socket/socket-ping) | Send a ping. | +| [Socket.send(data)](/javascript-api/k6-ws/socket/socket-send) | Send string data. | +| [Socket.sendBinary(data)](/javascript-api/k6-ws/socket/socket-sendbinary) | Send binary data. | +| [Socket.setInterval(callback, interval)](/javascript-api/k6-ws/socket/socket-setinterval) | Call a function repeatedly at certain intervals, while the connection is open. | +| [Socket.setTimeout(callback, period)](/javascript-api/k6-ws/socket/socket-settimeout) | Call a function with a delay, if the connection is open. | + + + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/10-connect- url- params- callback -.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/10-connect- url- params- callback -.md new file mode 100644 index 0000000000..c3a3838994 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/10-connect- url- params- callback -.md @@ -0,0 +1,50 @@ +--- +title: 'connect( url, params, callback )' +description: 'Create a WebSocket connection, and provides a Socket client to interact with the service.' +excerpt: 'Create a WebSocket connection, and provides a Socket client to interact with the service.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/connect/ +--- + + + +Initiate a WebSocket connection to a remote host. + +Calling connect will block the VU finalization until the WebSocket connection is closed. Instead of continuously looping the main function (`export default function() { ... }`) over an over, each VU will be halted listening to async events and executing their event handlers until the connection is closed. + +The following events can close the connection: + +- remote host close event. +- [Socket.close()](/javascript-api/k6-ws/socket/socket-close). +- k6 VU interruption based on test configuration or CLI commands. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| url | string | Request URL (e.g. "ws://echo.websocket.org"). | +| params | object | [Params](/javascript-api/k6-ws/params) object containing additional request parameters. | +| callback | function | The callback function that will be called when the WebSocket connection is initiated. A [Socket](/javascript-api/k6-ws/socket) object will be passed to the function, and this object can be used to set up callbacks etc when things happen on the WebSocket connection | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| [Response](/javascript-api/k6-http/response) | HTTP Response object. | + +### Example + + + +```javascript +import ws from 'k6/ws'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const resp = ws.connect(url, null, function (socket) { + socket.on('open', function () { + console.log('WebSocket connection established!'); + socket.close(); + }); + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/20-Params.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/20-Params.md new file mode 100644 index 0000000000..03e719e91e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/20-Params.md @@ -0,0 +1,44 @@ +--- +title: 'Params' +description: 'Used for setting various WebSocket request-specific parameters such as headers, tags, etc.' +excerpt: 'Used for setting various WebSocket request-specific parameters such as headers, tags, etc.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/params/ +--- + + + +_Params_ is an object used by the WebSocket methods that generate WebSocket requests. _Params_ contains request-specific options like headers that should be inserted into the request. + +| Name | Type | Description | +| --------------------- | ------ | ----------- | +| `Params.compression` | string | Compression algorithm to be used by the WebSocket connection. The only supported algorithm currently is `deflate`. If the option is left unset or empty, it defaults to no compression. | +| `Params.jar` | [http.CookieJar](/javascript-api/k6-http/cookiejar/) | The cookie jar that will be used when making the initial HTTP request to establish the WebSocket connection. If empty, the [default VU cookie jar](/javascript-api/k6-http/cookiejar-method) will be used. | +| `Params.headers` | object | Custom HTTP headers in key-value pairs that will be added to the initial HTTP request to establish the WebSocket connection. Keys are header names and values are header values. | +| `Params.tags` | object | [Custom metric tags](/using-k6/tags-and-groups/#user-defined-tags) in key-value pairs where the keys are names of tags and the values are tag values. The WebSocket connection will [generate metrics samples](/javascript-api/k6-ws/socket/#websocket-built-in-metrics) with these tags attached, allowing users to filter the results data or set [thresholds on sub-metrics](/using-k6/thresholds/#thresholds-on-tags). | + +### Example of custom metadata headers and tags + +_A k6 script that will make a WebSocket request with a custom header and tag results data with a specific tag_ + + + +```javascript +import ws from 'k6/ws'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { + headers: { 'X-MyHeader': 'k6test' }, + tags: { k6test: 'yes' }, + }; + const res = ws.connect(url, params, function (socket) { + socket.on('open', function () { + console.log('WebSocket connection established!'); + socket.close(); + }); + }); +} +``` + + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket.md new file mode 100644 index 0000000000..32ac9eb921 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket.md @@ -0,0 +1,89 @@ +--- +title: 'Socket' +excerpt: 'Socket is a WebSocket client to interact with a WebSocket connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/ +--- + + + +`Socket` is a WebSocket client to interact with a WebSocket connection. You can use it to listen various events happening on the WebSocket connection and send messages to the server. Additionally, you can use socket.setTimeout() and socket.setInterval() to execute code in the background, or repeatedly, while the WebSocket connection is open. + +| Method | Description | +| ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Socket.close()](/javascript-api/k6-ws/socket/socket-close) | Close the WebSocket connection. | +| [Socket.on(event, callback)](/javascript-api/k6-ws/socket/socket-on) | Set up an event listener on the connection for any of the following events:
- open
- binaryMessage
- message
- ping
- pong
- close
- error. | +| [Socket.ping()](/javascript-api/k6-ws/socket/socket-ping) | Send a ping. | +| [Socket.send(data)](/javascript-api/k6-ws/socket/socket-send) | Send string data. | +| [Socket.sendBinary(data)](/javascript-api/k6-ws/socket/socket-sendbinary) | Send binary data. | +| [Socket.setInterval(callback, interval)](/javascript-api/k6-ws/socket/socket-setinterval) | Call a function repeatedly at certain intervals, while the connection is open. | +| [Socket.setTimeout(callback, period)](/javascript-api/k6-ws/socket/socket-settimeout) | Call a function with a delay, if the connection is open. | + +### WebSocket built-in metrics + +`k6` automatically collects metrics when interacting with a WebSocket service through the `k6/ws` API. +Review the list in the [metrics reference](/using-k6/metrics/reference#websockets). + +Check out the [Results output article](/get-started/results-output) for more information about how to process the metric information. + +### Example + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const response = ws.connect(url, params, function (socket) { + socket.on('open', function open() { + console.log('connected'); + socket.send(Date.now()); + + socket.setInterval(function timeout() { + socket.ping(); + console.log('Pinging every 1sec (setInterval test)'); + }, 1000); + }); + + socket.on('ping', function () { + console.log('PING!'); + }); + + socket.on('pong', function () { + console.log('PONG!'); + }); + + socket.on('pong', function () { + // Multiple event handlers on the same event + console.log('OTHER PONG!'); + }); + + socket.on('message', function (message) { + console.log(`Received message: ${message}`); + }); + + socket.on('close', function () { + console.log('disconnected'); + }); + + socket.on('error', function (e) { + if (e.error() != 'websocket: close sent') { + console.log('An unexpected error occured: ', e.error()); + } + }); + + socket.setTimeout(function () { + console.log('2 seconds passed, closing the socket'); + socket.close(); + }, 2000); + }); + + check(response, { 'status is 101': (r) => r && r.status === 101 }); +} +//VU execution won't be completely finished until the connection is closed. +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-close--.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-close--.md new file mode 100644 index 0000000000..302bdccbc8 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-close--.md @@ -0,0 +1,33 @@ +--- +title: 'Socket.close([code])' +excerpt: 'Close the WebSocket connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-close/ +--- + + + +Close the WebSocket connection. + +| Parameter | Type | Description | +| --------------- | -------- | -------------------------------------------- | +| code (optional) | number | WebSocket status code. (default: 1001) | + + +### Example + + + +```javascript +import ws from 'k6/ws'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const response = ws.connect(url, null, function (socket) { + socket.on('open', function () { + socket.close(); + }); + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-on-event- callback-.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-on-event- callback-.md new file mode 100644 index 0000000000..b472cab052 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-on-event- callback-.md @@ -0,0 +1,85 @@ +--- +title: 'Socket.on(event, callback)' +excerpt: 'Set up callback functions for various events on the WebSocket connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-on/ +--- + + + +Set up callback functions for various events on the WebSocket connection. Multiple handlers can be defined for the same event. + +| Parameter | Type | Description | +| --------- | -------- | -------------------------------------------- | +| event | string | The event name to define a callback for. | +| callback | function | The function to call when the event happens. | + +| Event name | Description | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| open | Emitted when the connection is established | +| message | Emitted when a message is received from the server. | +| ping | Emitted when a ping is received from the server. The client will automatically send back a `pong`. | +| pong | Emitted when a pong is received from the server. | +| close | Emitted when the connection is closed by the client [Socket.close()](/javascript-api/k6-ws/socket/socket-close) or when the server sends the `close` event with code status 1000 (normal closure). | +| error | Emitted when an error occurs. Non-normal closure errors will be forwarded. | + +### Example + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const response = ws.connect(url, params, function (socket) { + socket.on('open', function open() { + console.log('connected'); + socket.send(Date.now()); + + socket.setInterval(function timeout() { + socket.ping(); + console.log('Pinging every 1sec (setInterval test)'); + }, 1000); + }); + + socket.on('ping', function () { + console.log('PING!'); + }); + + socket.on('pong', function () { + console.log('PONG!'); + }); + + socket.on('pong', function () { + // Multiple event handlers on the same event + console.log('OTHER PONG!'); + }); + + socket.on('message', function (message) { + console.log(`Received message: ${message}`); + }); + + socket.on('close', function () { + console.log('disconnected'); + }); + + socket.on('error', function (e) { + if (e.error() != 'websocket: close sent') { + console.log('An unexpected error occured: ', e.error()); + } + }); + + socket.setTimeout(function () { + console.log('2 seconds passed, closing the socket'); + socket.close(); + }, 2000); + }); + + check(response, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-ping--.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-ping--.md new file mode 100644 index 0000000000..7863e19482 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-ping--.md @@ -0,0 +1,33 @@ +--- +title: 'Socket.ping()' +excerpt: 'Send a ping. Ping messages can be used to verify that the remote endpoint is responsive.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-ping/ +--- + + + +Send a ping. Ping messages can be used to verify that the remote endpoint is responsive. + +### Example + + + +```javascript +import ws from 'k6/ws'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const response = ws.connect(url, null, function (socket) { + socket.on('open', function () { + socket.on('pong', function () { + // As required by the spec, when the ping is received, the recipient must send back a pong. + console.log('connection is alive'); + }); + + socket.ping(); + }); + }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-send-data-.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-send-data-.md new file mode 100644 index 0000000000..20fdfb7ce6 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-send-data-.md @@ -0,0 +1,36 @@ +--- +title: 'Socket.send(data)' +excerpt: 'Send a data string through the connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-send/ +--- + + + +Send a data string through the connection. +You can use `JSON.stringify` to convert a JSON or JavaScript values to a JSON string. + +| Parameter | Type | Description | +| --------- | ------ | ----------------- | +| data | string | The data to send. | + +### Example + + + +```javascript +import ws from 'k6/ws'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const response = ws.connect(url, null, function (socket) { + socket.on('open', function () { + socket.send('my-message'); + socket.send(JSON.stringify({ data: 'hola' })); + }); + }); +} +``` + + + +- See also [Socket.sendBinary(data)](/javascript-api/k6-ws/socket/socket-sendbinary) diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-sendBinary.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-sendBinary.md new file mode 100644 index 0000000000..158910cf93 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-sendBinary.md @@ -0,0 +1,40 @@ +--- +title: 'Socket.sendBinary(data)' +excerpt: 'Send binary data through the connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-sendbinary/ +--- + + + +Send binary data through the connection. + +| Parameter | Type | Description | +| --------- | ------ | ----------------- | +| data | ArrayBuffer | The data to send. | + +### Example + + + +```javascript +import ws from 'k6/ws'; + +const binFile = open('./file.pdf', 'b'); + +export default function () { + ws.connect('http://wshost/', function (socket) { + socket.on('open', function () { + socket.sendBinary(binFile); + }); + + socket.on('binaryMessage', function (msg) { + // msg is an ArrayBuffer, so we can wrap it in a typed array directly. + new Uint8Array(msg); + }); + }); +} +``` + + + +- See also [Socket.send(data)](/javascript-api/k6-ws/socket/socket-send) \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-setInterval-callback- interval-.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-setInterval-callback- interval-.md new file mode 100644 index 0000000000..388219c13c --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-setInterval-callback- interval-.md @@ -0,0 +1,47 @@ +--- +title: 'Socket.setInterval(callback, interval)' +excerpt: 'Call a function repeatedly, while the WebSocket connection is open.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-setinterval/ +--- + + + +Call a function repeatedly, while the WebSocket connection is open. + +| Parameter | Type | Description | +| --------- | -------- | ----------------------------------------------------------- | +| callback | function | The function to call every `interval` milliseconds. | +| interval | number | The number of milliseconds between two calls to `callback`. | + +### Example + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const res = ws.connect(url, params, function (socket) { + socket.on('open', function open() { + console.log('connected'); + + socket.setInterval(function timeout() { + socket.ping(); + console.log('Pinging every 1sec (setInterval test)'); + }, 1000); + }); + + socket.on('pong', function () { + console.log('PONG!'); + }); + }); + + check(res, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-setTimeout-callback- delay-.md b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-setTimeout-callback- delay-.md new file mode 100644 index 0000000000..0077abb87a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/12 k6-ws/80 Socket/Socket-setTimeout-callback- delay-.md @@ -0,0 +1,46 @@ +--- +title: 'Socket.setTimeout(callback, delay)' +excerpt: 'Call a function at a later time, if the WebSocket connection is still open then.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/k6-ws/socket/socket-settimeout/ +--- + + + +Call a function at a later time, if the WebSocket connection is still open then. + +| Parameter | Type | Description | +| --------- | -------- | ---------------------------------------------- | +| callback | function | The function to call when `delay` has expired. | +| delay | number | The delay time, in milliseconds. | + +### Example + + + +```javascript +import ws from 'k6/ws'; +import { sleep } from 'k6'; + +export default function () { + console.log('T0: Script started'); + const url = 'ws://echo.websocket.org'; + const response = ws.connect(url, null, function (socket) { + console.log('T0: Entered WebSockets run loop'); + socket.setTimeout(function () { + console.log('T0+1: This is printed'); + }, 1000); + socket.setTimeout(function () { + console.log('T0+2: Closing socket'); + socket.close(); + }, 2000); + socket.setTimeout(function () { + console.log('T0+3: This is not printed, because socket is closed'); + }, 3000); + }); + console.log('T0+2: Exited WebSockets run loop'); + sleep(2); + console.log('T0+4: Script finished'); +} +``` + + diff --git a/src/data/markdown/docs/02 javascript api/90 Error Codes.md b/src/data/markdown/docs/02 javascript api/90 Error Codes.md index c8f25ba2a9..ab1d7804f2 100644 --- a/src/data/markdown/docs/02 javascript api/90 Error Codes.md +++ b/src/data/markdown/docs/02 javascript api/90 Error Codes.md @@ -2,7 +2,50 @@ title: 'Error Codes' excerpt: 'Error codes are unique numbers that can be used to identify and handle different application and network errors more easily.' canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/error-codes/ -redirect: https://grafana.com/docs/k6/latest/javascript-api/error-codes/ --- Error codes are unique numbers that can be used to identify and handle different application and network errors more easily. For the moment, these error codes are applicable only for errors that happen during HTTP requests, but they will be reused and extended to support other protocols in future k6 releases. + +When an error occurs, its code is determined and returned as both the `error_code` field of the [`http.Response`](/javascript-api/k6-http/response) object, and also attached as the `error_code` [tag](/using-k6/tags-and-groups) to any [metrics](/using-k6/metrics) associated with that request. Additionally, for more details, the `error` metric tag and `http.Response` field will still contain the actual string error message. + +Error codes for different errors are as distinct as possible, but for easier handling and grouping, codes in different error categories are also grouped in broad ranges. The current error code ranges are: + +- 1000-1099 - General errors +- 1100-1199 - DNS errors +- 1200-1299 - TCP errors +- 1300-1399 - TLS errors +- 1400-1499 - HTTP 4xx errors +- 1500-1599 - HTTP 5xx errors +- 1600-1699 - HTTP/2 specific errors + +The following specific error codes are currently defined: + +- 1000: A generic error that isn't any of the ones listed below. +- 1010: A non-TCP network error - this is a place holder there is no error currently known to trigger it. +- 1020: An invalid URL was specified. +- 1050: The HTTP request has timed out. +- 1100: A generic DNS error that isn't any of the ones listed below. +- 1101: No IP for the provided host was found. +- 1110: Blacklisted IP was resolved or a connection to such was tried to be established. +- 1111: Blacklisted hostname using The [Block Hostnames](/using-k6/k6-options/reference#block-hostnames) option. +- 1200: A generic TCP error that isn't any of the ones listed below. +- 1201: A "broken pipe" on write - the other side has likely closed the connection. +- 1202: An unknown TCP error - We got an error that we don't recognize but it is from the operating system and has `errno` set on it. The message in `error` includes the operation(write,read) and the errno, the OS, and the original message of the error. +- 1210: General TCP dial error. +- 1211: Dial timeout error - the timeout for the dial was reached. +- 1212: Dial connection refused - the connection was refused by the other party on dial. +- 1213: Dial unknown error. +- 1220: Reset by peer - the connection was reset by the other party, most likely a server. +- 1300: General TLS error +- 1310: Unknown authority - the certificate issuer is unknown. +- 1311: The certificate doesn't match the hostname. +- 1400 to 1499: error codes that correspond to the [HTTP 4xx status codes for client errors](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors) +- 1500 to 1599: error codes that correspond to the [HTTP 5xx status codes for server errors](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors) +- 1600: A generic HTTP/2 error that isn't any of the ones listed below. +- 1610: A general HTTP/2 GoAway error. +- 1611 to 1629: HTTP/2 GoAway errors with the value of the specific [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) added to 1611. +- 1630: A general HTTP/2 stream error. +- 1631 to 1649: HTTP/2 stream errors with the value of the specific [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) added to 1631. +- 1650: A general HTTP/2 connection error. +- 1651 to 1669: HTTP/2 connection errors with the value of the specific [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) added to 1651. +- 1701: Decompression error. diff --git a/src/data/markdown/docs/02 javascript api/alternative main modules/06 k6-execution.md b/src/data/markdown/docs/02 javascript api/alternative main modules/06 k6-execution.md new file mode 100644 index 0000000000..52f1ef1c8a --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/alternative main modules/06 k6-execution.md @@ -0,0 +1,47 @@ +--- +title: "k6/execution" +shouldCreatePage: false +--- + +The `k6/execution` module provides the test execution information with the following properties: +- [instance](/javascript-api/k6-execution/#instance) +- [scenario](/javascript-api/k6-execution/#scenario) +- [test](/javascript-api/k6-execution/#vu) +- [vu](/javascript-api/k6-execution/#vu) + +[instance](/javascript-api/k6-execution/#instance) + +| Property | Type | Description | +|------------------------|---------|--------------------------------------------------------------------------| +| iterationsInterrupted | integer | The number of prematurely interrupted iterations in the current instance. | +| iterationsCompleted | integer | The number of completed iterations in the current instance. | +| vusActive | integer | The number of active VUs. | +| vusInitialized | integer | The number of currently initialized VUs. | +| currentTestRunDuration | float | The time passed from the start of the current test run in milliseconds. | + +[scenario](/javascript-api/k6-execution/#scenario) + +| Property | Type | Description | +|---------------------|---------|--------------------------------------------------------------------------| +| name | string | The assigned name of the running scenario. | +| executor | string | The name of the running [Executor](/using-k6/scenarios/#executors) type. | +| startTime | integer | The Unix timestamp in milliseconds when the scenario started. | +| progress | float | Percentage in a 0 to 1 interval of the scenario progress. | +| iterationInInstance | integer | The unique and zero-based sequential number of the current iteration in the scenario, across the current instance. | +| iterationInTest | integer | The unique and zero-based sequential number of the current iteration in the scenario. It is unique in all k6 execution modes - in local, cloud and distributed/segmented test runs. However, while every instance will get non-overlapping index values in cloud/distributed tests, they might iterate over them at different speeds, so the values won't be sequential across them. | + +[test](/javascript-api/k6-execution/#test) + +| Property | Type | Description | +|----------|------|-------------| +| abort([String]) | function | It aborts the test run with the exit code `108`, and an optional string parameter can provide an error message. Aborting the test will not prevent the `teardown()` execution. | +| options | Object | It returns an object with all the test options as properties. The options' values are consolidated following the [order of precedence](/using-k6/k6-options/how-to#order-of-precedence) and derived if shortcuts have been used. It returns `null` for properties where the relative option hasn't been defined. | + +[vu](/javascript-api/k6-execution/#vu) + +| Property | Type | Description | +|---------------------|---------|--------------------------------------------------------------------------| +| iterationInInstance | integer | The identifier of the iteration in the current instance. | +| iterationInScenario | integer | The identifier of the iteration in the current scenario. | +| idInInstance | integer | The identifier of the VU across the instance. | +| idInTest | integer | The globally unique (across the whole test run) identifier of the VU. | diff --git a/src/data/markdown/docs/02 javascript api/alternative main modules/10 k6-net-grpc.md b/src/data/markdown/docs/02 javascript api/alternative main modules/10 k6-net-grpc.md new file mode 100644 index 0000000000..2b4f7ac83e --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/alternative main modules/10 k6-net-grpc.md @@ -0,0 +1,23 @@ +--- +title: "k6/net/grpc" +shouldCreatePage: false +--- + +The `k6/net/grpc` module, added in k6 v0.29.0, provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2. + +
+ +The k6 gRPC API is currently considered in beta and is subject to change. Future k6 versions might have slight differences in the method and type signatures described in this documentation. + +
+ +| Class/Method | Description | +|--------------|-------------| +| [Client](/javascript-api/k6-net-grpc/client) | gRPC client used for making RPC calls to a gRPC Server. | +| [Client.load(importPaths, ...protoFiles)](/javascript-api/k6-net-grpc/client/client-load) | Loads and parses the given protocol buffer definitions to be made available for RPC requests. | +| [Client.connect(address [,params])](/javascript-api/k6-net-grpc/client/client-connect) | Connects to a given gRPC service. | +| [Client.invoke(url, request [,params])](/javascript-api/k6-net-grpc/client/client-invoke) | Makes an unary RPC for the given service/method and returns a [Response](/javascript-api/k6-net-grpc/response). | +| [Client.close()](/javascript-api/k6-net-grpc/client/client-close) | Close the connection to the gRPC service. | +| [Params](/javascript-api/k6-net-grpc/params) | RPC Request specific options. | +| [Response](/javascript-api/k6-net-grpc/response) | Returned by RPC requests. | +| [Constants](/javascript-api/k6-net-grpc/constants) | Define constants to distinguish between [gRPC Response](/javascript-api/k6-net-grpc/response) statuses. | \ No newline at end of file diff --git a/src/data/markdown/docs/02 javascript api/alternative main modules/12 Error Codes.md b/src/data/markdown/docs/02 javascript api/alternative main modules/12 Error Codes.md new file mode 100644 index 0000000000..fce204ca14 --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/alternative main modules/12 Error Codes.md @@ -0,0 +1,38 @@ +--- +title: 'Error Codes' +shouldCreatePage: false +--- + +The following specific error codes are currently defined: + +- 1000: A generic error that isn't any of the ones listed below. +- 1010: A non-TCP network error - this is a place holder there is no error currently known to trigger it. +- 1020: An invalid URL was specified. +- 1050: The HTTP request has timed out. +- 1100: A generic DNS error that isn't any of the ones listed below. +- 1101: No IP for the provided host was found. +- 1110: Blacklisted IP was resolved or a connection to such was tried to be established. +- 1111: Blacklisted hostname using The [Block Hostnames](/using-k6/k6-options/reference#block-hostnames) option. +- 1200: A generic TCP error that isn't any of the ones listed below. +- 1201: A "broken pipe" on write - the other side has likely closed the connection. +- 1202: An unknown TCP error - We got an error that we don't recognize but it is from the operating system and has `errno` set on it. The message in `error` includes the operation(write,read) and the errno, the OS, and the original message of the error. +- 1210: General TCP dial error. +- 1211: Dial timeout error - the timeout for the dial was reached. +- 1212: Dial connection refused - the connection was refused by the other party on dial. +- 1213: Dial unknown error. +- 1220: Reset by peer - the connection was reset by the other party, most likely a server. +- 1300: General TLS error +- 1310: Unknown authority - the certificate issuer is unknown. +- 1311: The certificate doesn't match the hostname. +- 1400 to 1499: error codes that correspond to the [HTTP 4xx status codes for client errors](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors) +- 1500 to 1599: error codes that correspond to the [HTTP 5xx status codes for server errors](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors) +- 1600: A generic HTTP/2 error that isn't any of the ones listed below. +- 1610: A general HTTP/2 GoAway error. +- 1611 to 1629: HTTP/2 GoAway errors with the value of the specific [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) added to 1611. +- 1630: A general HTTP/2 stream error. +- 1631 to 1649: HTTP/2 stream errors with the value of the specific [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) added to 1631. +- 1650: A general HTTP/2 connection error. +- 1651 to 1669: HTTP/2 connection errors with the value of the specific [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) added to 1651. +- 1701: Decompression error. + +Read more about [Error Codes](/javascript-api/error-codes/) diff --git a/src/data/markdown/docs/02 javascript api/alternative main modules/20 jslib.md b/src/data/markdown/docs/02 javascript api/alternative main modules/20 jslib.md new file mode 100644 index 0000000000..4240615b1d --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/alternative main modules/20 jslib.md @@ -0,0 +1,14 @@ +--- +title: "jslib" +shouldCreatePage: false +--- + +The [jslib.k6.io](https://jslib.k6.io/) is a collection of external JavaScript libraries that can be [directly imported](/using-k6/modules#remote-http-s-modules) in k6 scripts. + + +| Library | Description | +| -------- | ----------- | +| [utils](https://k6.io/docs/javascript-api/jslib/utils) | Small utility functions useful in every day load testing | +| [expect](/javascript-api/jslib/expect) | Micro-framework for writing tests in a style of Jest or ava. | +| [httpx](/javascript-api/jslib/httpx) | Wrapper around the http that simplifies session handling | + diff --git a/src/data/markdown/docs/02 javascript api/alternative main modules/30 k6-x-browser.md b/src/data/markdown/docs/02 javascript api/alternative main modules/30 k6-x-browser.md new file mode 100644 index 0000000000..a9463ebc8f --- /dev/null +++ b/src/data/markdown/docs/02 javascript api/alternative main modules/30 k6-x-browser.md @@ -0,0 +1,27 @@ +--- +title: "k6/x/browser" +shouldCreatePage: false +--- + +`xk6-browser` uses [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) to instrument and interact with the browser. The `xk6-browser` APIs aims for rough compatibility with the [Playwright API for NodeJS](https://playwright.dev/docs/api/class-playwright). + +Here's a list of the fully (✅) or partially (🚧) implemented classes of the Playwright API: + + + +- 🚧 [Browser](/javascript-api/xk6-browser/api/browser/) +- 🚧 [BrowserContext](/javascript-api/xk6-browser/api/browsercontext/) +- 🚧 [BrowserType](/javascript-api/xk6-browser/api/browsertype/) +- 🚧 [ElementHandle](/javascript-api/xk6-browser/api/elementhandle/) +- 🚧 [Frame](/javascript-api/xk6-browser/api/frame/) +- ✅ [JSHandle](/javascript-api/xk6-browser/api/jshandle) +- ✅ [Keyboard](/javascript-api/xk6-browser/api/keyboard) +- 🚧 [Locator](/javascript-api/xk6-browser/api/locator/) +- ✅ [Mouse](/javascript-api/xk6-browser/api/mouse/) +- 🚧 [Page](/javascript-api/xk6-browser/api/page/) +- 🚧 [Request](/javascript-api/xk6-browser/api/request/) +- 🚧 [Response](/javascript-api/xk6-browser/api/response/) +- 🚧 [Browser](/javascript-api/xk6-browser/api/browser/) +- ✅ [Touchscreen](/javascript-api/xk6-browser/api/touchscreen/) + + \ No newline at end of file diff --git a/src/data/markdown/docs/04 integrations/01 Test authoring/01 test-builder.md b/src/data/markdown/docs/04 integrations/01 Test authoring/01 test-builder.md new file mode 100644 index 0000000000..622d6e0209 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/01 Test authoring/01 test-builder.md @@ -0,0 +1,4 @@ +--- +title: 'Test Builder' +redirect: 'https://k6.io/docs/test-authoring/test-builder' +--- diff --git a/src/data/markdown/docs/04 integrations/01 Test authoring/02 browser-recorder.md b/src/data/markdown/docs/04 integrations/01 Test authoring/02 browser-recorder.md new file mode 100644 index 0000000000..b5eeca052b --- /dev/null +++ b/src/data/markdown/docs/04 integrations/01 Test authoring/02 browser-recorder.md @@ -0,0 +1,4 @@ +--- +title: 'Browser Recorder' +redirect: 'https://k6.io/docs/test-authoring/create-tests-from-recordings/using-the-browser-recorder/' +--- diff --git a/src/data/markdown/docs/04 integrations/02 IDE extensions/01 vscode.md b/src/data/markdown/docs/04 integrations/02 IDE extensions/01 vscode.md new file mode 100644 index 0000000000..d5c3780cf0 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/02 IDE extensions/01 vscode.md @@ -0,0 +1,4 @@ +--- +title: 'VS Code Extension' +redirect: 'https://marketplace.visualstudio.com/items?itemName=k6.k6' +--- diff --git a/src/data/markdown/docs/04 integrations/02 IDE extensions/02 intellij.md b/src/data/markdown/docs/04 integrations/02 IDE extensions/02 intellij.md new file mode 100644 index 0000000000..67ac054efc --- /dev/null +++ b/src/data/markdown/docs/04 integrations/02 IDE extensions/02 intellij.md @@ -0,0 +1,4 @@ +--- +title: 'IntelliJ IDEA' +redirect: 'https://plugins.jetbrains.com/plugin/16141-k6' +--- diff --git a/src/data/markdown/docs/04 integrations/02 IDE extensions/03 intellisense.md b/src/data/markdown/docs/04 integrations/02 IDE extensions/03 intellisense.md new file mode 100644 index 0000000000..47b3e0d680 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/02 IDE extensions/03 intellisense.md @@ -0,0 +1,4 @@ +--- +title: 'IntelliSense' +redirect: 'https://k6.io/docs/misc/intellisense' +--- diff --git a/src/data/markdown/docs/04 integrations/03 Converters/01 har-to-k6.md b/src/data/markdown/docs/04 integrations/03 Converters/01 har-to-k6.md new file mode 100644 index 0000000000..0d39bd7bbe --- /dev/null +++ b/src/data/markdown/docs/04 integrations/03 Converters/01 har-to-k6.md @@ -0,0 +1,4 @@ +--- +title: 'HAR-to-k6' +redirect: 'https://github.com/k6io/har-to-k6' +--- diff --git a/src/data/markdown/docs/04 integrations/03 Converters/03 postman-to-k6.md b/src/data/markdown/docs/04 integrations/03 Converters/03 postman-to-k6.md new file mode 100644 index 0000000000..170ef1fc15 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/03 Converters/03 postman-to-k6.md @@ -0,0 +1,4 @@ +--- +title: 'Postman-to-k6' +redirect: 'https://github.com/apideck-libraries/postman-to-k6' +--- diff --git a/src/data/markdown/docs/04 integrations/03 Converters/04 openapi-generator.md b/src/data/markdown/docs/04 integrations/03 Converters/04 openapi-generator.md new file mode 100644 index 0000000000..4c62510987 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/03 Converters/04 openapi-generator.md @@ -0,0 +1,4 @@ +--- +title: 'OpenAPI generator' +redirect: 'https://k6.io/blog/load-testing-your-api-with-swagger-openapi-and-k6' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 amazon-cloudwatch.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 amazon-cloudwatch.md new file mode 100644 index 0000000000..b39f2f7fb3 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 amazon-cloudwatch.md @@ -0,0 +1,4 @@ +--- +title: 'Amazon CloudWatch' +redirect: 'https://k6.io/docs/results-output/real-time/amazon-cloudwatch' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 apache-kafka.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 apache-kafka.md new file mode 100644 index 0000000000..29ccb83335 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 apache-kafka.md @@ -0,0 +1,4 @@ +--- +title: 'Apache Kafka' +redirect: 'https://k6.io/docs/results-output/real-time/apache-kafka' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 cloud-service.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 cloud-service.md new file mode 100644 index 0000000000..f60da1f903 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 cloud-service.md @@ -0,0 +1,4 @@ +--- +title: 'Cloud' +redirect: 'https://k6.io/docs/results-output/real-time/cloud' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 csv.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 csv.md new file mode 100644 index 0000000000..4f894f5466 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 csv.md @@ -0,0 +1,4 @@ +--- +title: 'CSV' +redirect: 'https://k6.io/docs/results-output/real-time/csv' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 datadog.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 datadog.md new file mode 100644 index 0000000000..e8b980d364 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 datadog.md @@ -0,0 +1,4 @@ +--- +title: 'Datadog' +redirect: 'https://k6.io/docs/results-output/real-time/datadog' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 dynatrace.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 dynatrace.md new file mode 100644 index 0000000000..bf64e3ed76 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 dynatrace.md @@ -0,0 +1,4 @@ +--- +title: 'Dynatrace' +redirect: 'https://k6.io/docs/results-output/real-time/dynatrace' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 elasticsearch.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 elasticsearch.md new file mode 100644 index 0000000000..ff82702aa5 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 elasticsearch.md @@ -0,0 +1,4 @@ +--- +title: 'Elasticsearch' +redirect: 'https://k6.io/docs/results-output/real-time/elasticsearch' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 grafana-cloud.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 grafana-cloud.md new file mode 100644 index 0000000000..47b06f55ba --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 grafana-cloud.md @@ -0,0 +1,4 @@ +--- +title: 'Grafana Cloud Prometheus' +redirect: 'https://k6.io/docs/results-output/real-time/grafana-cloud-prometheus/' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 influxdb-grafana.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 influxdb-grafana.md new file mode 100644 index 0000000000..c38a7b608b --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 influxdb-grafana.md @@ -0,0 +1,4 @@ +--- +title: 'InfluxDB' +redirect: 'https://k6.io/docs/results-output/real-time/influxdb' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 json.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 json.md new file mode 100644 index 0000000000..a76f762515 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 json.md @@ -0,0 +1,4 @@ +--- +title: 'JSON' +redirect: 'https://k6.io/docs/results-output/real-time/json' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 netdata.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 netdata.md new file mode 100644 index 0000000000..f41dcc88a9 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 netdata.md @@ -0,0 +1,4 @@ +--- +title: 'Netdata' +redirect: 'https://k6.io/docs/results-output/real-time/netdata/' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 new-relic.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 new-relic.md new file mode 100644 index 0000000000..b913655cca --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 new-relic.md @@ -0,0 +1,4 @@ +--- +title: 'New Relic' +redirect: 'https://k6.io/docs/results-output/real-time/new-relic' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 prometheus.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 prometheus.md new file mode 100644 index 0000000000..72de356226 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 prometheus.md @@ -0,0 +1,4 @@ +--- +title: 'Prometheus' +redirect: 'https://k6.io/docs/results-output/real-time/prometheus-remote-write' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 statsd.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 statsd.md new file mode 100644 index 0000000000..64227ca619 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 statsd.md @@ -0,0 +1,4 @@ +--- +title: 'StatsD' +redirect: 'https://k6.io/docs/results-output/real-time/statsd' +--- diff --git a/src/data/markdown/docs/04 integrations/04 Results visualization/00 timescaledb.md b/src/data/markdown/docs/04 integrations/04 Results visualization/00 timescaledb.md new file mode 100644 index 0000000000..5dc1872070 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/04 Results visualization/00 timescaledb.md @@ -0,0 +1,4 @@ +--- +title: 'TimescaleDB' +redirect: 'https://k6.io/docs/results-output/real-time/timescaledb' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/01 aws-codebuild.md b/src/data/markdown/docs/04 integrations/05 CI tools/01 aws-codebuild.md new file mode 100644 index 0000000000..df2f888b5c --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/01 aws-codebuild.md @@ -0,0 +1,4 @@ +--- +title: 'AWS CodeBuild' +redirect: 'https://k6.io/blog/integrating-k6-with-aws-codebuild/' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/02 azure.md b/src/data/markdown/docs/04 integrations/05 CI tools/02 azure.md new file mode 100644 index 0000000000..b3aeb000ee --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/02 azure.md @@ -0,0 +1,4 @@ +--- +title: 'Azure Pipelines' +redirect: 'https://k6.io/blog/integrating-load-testing-with-azure-pipelines' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/03 bamboo.md b/src/data/markdown/docs/04 integrations/05 CI tools/03 bamboo.md new file mode 100644 index 0000000000..a71f793fa2 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/03 bamboo.md @@ -0,0 +1,4 @@ +--- +title: 'Buddy' +redirect: 'https://k6.io/blog/integrating-k6-with-buddy-devops/' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/04 buddy.md b/src/data/markdown/docs/04 integrations/05 CI tools/04 buddy.md new file mode 100644 index 0000000000..5cd57cfa10 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/04 buddy.md @@ -0,0 +1,4 @@ +--- +title: 'Bamboo' +redirect: 'https://k6.io/blog/integrating-k6-with-bamboo' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/05 circleci.md b/src/data/markdown/docs/04 integrations/05 CI tools/05 circleci.md new file mode 100644 index 0000000000..aadb5d1a22 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/05 circleci.md @@ -0,0 +1,4 @@ +--- +title: 'CircleCI' +redirect: 'https://k6.io/blog/integrating-load-testing-with-circleci' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/06 flagger.md b/src/data/markdown/docs/04 integrations/05 CI tools/06 flagger.md new file mode 100644 index 0000000000..dc133c9d09 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/06 flagger.md @@ -0,0 +1,4 @@ +--- +title: 'Flagger' +redirect: 'https://docs.flagger.app/usage/webhooks#k6-load-tester' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/07 github.md b/src/data/markdown/docs/04 integrations/05 CI tools/07 github.md new file mode 100644 index 0000000000..a98c947e7a --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/07 github.md @@ -0,0 +1,4 @@ +--- +title: 'GitHub Actions' +redirect: 'https://k6.io/blog/load-testing-using-github-actions' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/08 gitlab.md b/src/data/markdown/docs/04 integrations/05 CI tools/08 gitlab.md new file mode 100644 index 0000000000..526c9b7c6f --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/08 gitlab.md @@ -0,0 +1,4 @@ +--- +title: 'GitLab' +redirect: 'https://k6.io/blog/integrating-load-testing-with-gitlab' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/09 google-cloud.md b/src/data/markdown/docs/04 integrations/05 CI tools/09 google-cloud.md new file mode 100644 index 0000000000..ecabc1a81a --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/09 google-cloud.md @@ -0,0 +1,4 @@ +--- +title: 'Google Cloud Build' +redirect: 'https://k6.io/blog/integrating-k6-with-google-cloud-build/' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/10 jenkins.md b/src/data/markdown/docs/04 integrations/05 CI tools/10 jenkins.md new file mode 100644 index 0000000000..47e262ea67 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/10 jenkins.md @@ -0,0 +1,4 @@ +--- +title: 'Jenkins' +redirect: 'https://k6.io/blog/integrating-load-testing-with-jenkins' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/11 keptn.md b/src/data/markdown/docs/04 integrations/05 CI tools/11 keptn.md new file mode 100644 index 0000000000..73d14f96cd --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/11 keptn.md @@ -0,0 +1,4 @@ +--- +title: 'Keptn' +redirect: 'https://k6.io/blog/performance-testing-in-keptn-using-k6/' +--- diff --git a/src/data/markdown/docs/04 integrations/05 CI tools/12 teamcity.md b/src/data/markdown/docs/04 integrations/05 CI tools/12 teamcity.md new file mode 100644 index 0000000000..3ab4270c60 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/05 CI tools/12 teamcity.md @@ -0,0 +1,4 @@ +--- +title: 'TeamCity' +redirect: 'https://k6.io/blog/load-testing-using-teamcity-and-k6' +--- diff --git a/src/data/markdown/docs/04 integrations/06 Chaos engineering/01 steadybit.md b/src/data/markdown/docs/04 integrations/06 Chaos engineering/01 steadybit.md new file mode 100644 index 0000000000..2637d22769 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/06 Chaos engineering/01 steadybit.md @@ -0,0 +1,4 @@ +--- +title: 'Steadybit' +redirect: 'https://k6.io/blog/chaos-engineering-with-k6-and-steadybit' +--- \ No newline at end of file diff --git a/src/data/markdown/docs/04 integrations/06 Chaos engineering/02 xk6-disruptor.md b/src/data/markdown/docs/04 integrations/06 Chaos engineering/02 xk6-disruptor.md new file mode 100644 index 0000000000..cb8b4b6f8d --- /dev/null +++ b/src/data/markdown/docs/04 integrations/06 Chaos engineering/02 xk6-disruptor.md @@ -0,0 +1,4 @@ +--- +title: 'xk6-disruptor' +redirect: 'https://k6.io/docs/javascript-api/xk6-disruptor/' +--- diff --git a/src/data/markdown/docs/04 integrations/06 Chaos engineering/03 chaostoolkit.md b/src/data/markdown/docs/04 integrations/06 Chaos engineering/03 chaostoolkit.md new file mode 100644 index 0000000000..d6863a44b2 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/06 Chaos engineering/03 chaostoolkit.md @@ -0,0 +1,4 @@ +--- +title: 'ChaosToolkit' +redirect: 'http://chaostoolkit.org/drivers/k6/' +--- diff --git a/src/data/markdown/docs/04 integrations/07 Test management/01 azuretest.md b/src/data/markdown/docs/04 integrations/07 Test management/01 azuretest.md new file mode 100644 index 0000000000..f0a962c5e5 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/07 Test management/01 azuretest.md @@ -0,0 +1,4 @@ +--- +title: 'Azure Test Plan' +redirect: 'https://medium.com/microsoftazure/load-testing-with-azure-devops-and-k6-839be039b68a' +--- \ No newline at end of file diff --git a/src/data/markdown/docs/04 integrations/07 Test management/02 testrail.md b/src/data/markdown/docs/04 integrations/07 Test management/02 testrail.md new file mode 100644 index 0000000000..814fdfe875 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/07 Test management/02 testrail.md @@ -0,0 +1,4 @@ +--- +title: 'TestRail' +redirect: 'https://dev.to/kwidera/introducing-testrail-in-you-k6-tests-eck' +--- diff --git a/src/data/markdown/docs/04 integrations/07 Test management/03 testkube.md b/src/data/markdown/docs/04 integrations/07 Test management/03 testkube.md new file mode 100644 index 0000000000..256d7455c8 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/07 Test management/03 testkube.md @@ -0,0 +1,4 @@ +--- +title: 'Testkube' +redirect: 'https://kubeshop.github.io/testkube/test-types/executor-k6' +--- diff --git a/src/data/markdown/docs/04 integrations/07 Test management/04 xray.md b/src/data/markdown/docs/04 integrations/07 Test management/04 xray.md new file mode 100644 index 0000000000..5f4e8ac1e3 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/07 Test management/04 xray.md @@ -0,0 +1,4 @@ +--- +title: 'Xray' +redirect: 'https://docs.getxray.app/display/XRAYCLOUD/Performance+and+load+testing+with+k6' +--- diff --git a/src/data/markdown/docs/04 integrations/07 Test management/05 tracetest.md b/src/data/markdown/docs/04 integrations/07 Test management/05 tracetest.md new file mode 100644 index 0000000000..bb69e0aec2 --- /dev/null +++ b/src/data/markdown/docs/04 integrations/07 Test management/05 tracetest.md @@ -0,0 +1,4 @@ +--- +title: 'Tracetest' +redirect: 'https://docs.tracetest.io/tools-and-integrations/integrations/k6' +--- diff --git a/src/data/markdown/docs/05 Examples/01 Examples/01 single-request.md b/src/data/markdown/docs/05 Examples/01 Examples/01 single-request.md index 369099a03e..bdfb8c8219 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/01 single-request.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/01 single-request.md @@ -3,7 +3,6 @@ title: 'Single request' excerpt: 'Example of one HTTP GET request' draft: 'false' canonicalUrl: https://grafana.com/docs/k6/latest/examples/single-request/ -redirect: https://grafana.com/docs/k6/latest/examples/single-request/ --- diff --git a/src/data/markdown/docs/05 Examples/01 Examples/02 http-authentication.md b/src/data/markdown/docs/05 Examples/01 Examples/02 http-authentication.md index 94c9d788d9..7fbd756f3d 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/02 http-authentication.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/02 http-authentication.md @@ -2,7 +2,6 @@ title: 'HTTP Authentication' excerpt: 'Scripting examples on how to use different authentication or authorization methods in your load test.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/http-authentication/ -redirect: https://grafana.com/docs/k6/latest/examples/http-authentication/ --- Scripting examples on how to use different authentication or authorization methods in your load test. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/03 oauth-authentication.md b/src/data/markdown/docs/05 Examples/01 Examples/03 oauth-authentication.md index 229c13d157..49f601f89d 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/03 oauth-authentication.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/03 oauth-authentication.md @@ -2,7 +2,6 @@ title: 'OAuth Authentication' excerpt: 'Scripting examples on how to use OAuth authentication in your load test.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/oauth-authentication/ -redirect: https://grafana.com/docs/k6/latest/examples/oauth-authentication/ --- Scripting examples on how to use OAuth authentication in your load test. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/04 correlation-and-dynamic-data.md b/src/data/markdown/docs/05 Examples/01 Examples/04 correlation-and-dynamic-data.md index f3bd73d4be..1e0441dc86 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/04 correlation-and-dynamic-data.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/04 correlation-and-dynamic-data.md @@ -6,7 +6,6 @@ excerpt: | This is due to the fact that those tools will capture session IDs, CSRF tokens, VIEWSTATE, wpnonce, and other dynamic values from your specific session. canonicalUrl: https://grafana.com/docs/k6/latest/examples/correlation-and-dynamic-data/ -redirect: https://grafana.com/docs/k6/latest/examples/correlation-and-dynamic-data/ --- Scripting examples on how to correlate dynamic data in your test script. Correlation is often diff --git a/src/data/markdown/docs/05 Examples/01 Examples/05 data-parameterization.md b/src/data/markdown/docs/05 Examples/01 Examples/05 data-parameterization.md index 0606f1ea70..696b984e44 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/05 data-parameterization.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/05 data-parameterization.md @@ -7,7 +7,6 @@ excerpt: | Parameterization helps to prevent server-side caching from impacting your load test. This will, in turn, make your test more realistic. canonicalUrl: https://grafana.com/docs/k6/latest/examples/data-parameterization/ -redirect: https://grafana.com/docs/k6/latest/examples/data-parameterization/ --- _Data parameterization_ is the process of turning test values into reusable parameters, for example, through variables and shared arrays. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/06 parse-html.md b/src/data/markdown/docs/05 Examples/01 Examples/06 parse-html.md index ae627f57b8..729914aa0d 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/06 parse-html.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/06 parse-html.md @@ -2,7 +2,6 @@ title: 'Parse HTML' excerpt: 'Scripting examples parsing HTML content.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/parse-html/ -redirect: https://grafana.com/docs/k6/latest/examples/parse-html/ --- Examples parsing HTML content. Use the `k6/html` module for HTML parsing. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/07 html-forms.md b/src/data/markdown/docs/05 Examples/01 Examples/07 html-forms.md index 7daa381d4a..8ce4bff509 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/07 html-forms.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/07 html-forms.md @@ -2,7 +2,6 @@ title: 'HTML Forms' excerpt: 'Scripting example on how to handle HTML forms in a k6 test.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/html-forms/ -redirect: https://grafana.com/docs/k6/latest/examples/html-forms/ --- Scripting example on how to handle HTML forms. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/08 cookies-example.md b/src/data/markdown/docs/05 Examples/01 Examples/08 cookies-example.md index 3b868ae1ed..d081b30b4e 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/08 cookies-example.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/08 cookies-example.md @@ -2,7 +2,6 @@ title: 'Cookies Example' excerpt: 'Scripting examples on how you can interact with cookies during your load test if required.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/cookies-example/ -redirect: https://grafana.com/docs/k6/latest/examples/cookies-example/ --- Scripting examples on how you can interact with cookies during your load test if required. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/09 data-uploads.md b/src/data/markdown/docs/05 Examples/01 Examples/09 data-uploads.md index 0639c8d9d3..d4125148a3 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/09 data-uploads.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/09 data-uploads.md @@ -2,7 +2,6 @@ title: 'Data Uploads' excerpt: 'Scripting examples on how to execute a load test that will upload a file to the System Under Test (SUT).' canonicalUrl: https://grafana.com/docs/k6/latest/examples/data-uploads/ -redirect: https://grafana.com/docs/k6/latest/examples/data-uploads/ --- Example to execute a load test that will upload a file to the System Under Test (SUT). diff --git a/src/data/markdown/docs/05 Examples/01 Examples/10 api-crud-operations.md b/src/data/markdown/docs/05 Examples/01 Examples/10 api-crud-operations.md index c9e985dbdc..5be8364d98 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/10 api-crud-operations.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/10 api-crud-operations.md @@ -2,7 +2,6 @@ title: 'API CRUD Operations' excerpt: 'This example covers the usage of k6 to test a REST API CRUD operations.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/api-crud-operations/ -redirect: https://grafana.com/docs/k6/latest/examples/api-crud-operations/ --- The examples showcase the testing of CRUD operations on a REST API. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/11 generating-uuids.md b/src/data/markdown/docs/05 Examples/01 Examples/11 generating-uuids.md index 81296a294e..5c1dd80917 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/11 generating-uuids.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/11 generating-uuids.md @@ -2,7 +2,6 @@ title: 'Generating UUIDs' excerpt: 'Scripting example on how to generate UUIDs in your load test.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/generating-uuids/ -redirect: https://grafana.com/docs/k6/latest/examples/generating-uuids/ --- If you want to make a version 4 UUID, diff --git a/src/data/markdown/docs/05 Examples/01 Examples/12 http2.md b/src/data/markdown/docs/05 Examples/01 Examples/12 http2.md index 75859aadc7..a69221ea06 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/12 http2.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/12 http2.md @@ -2,7 +2,6 @@ title: 'HTTP2' excerpt: 'Information on how to load test HTTP/2.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/http2/ -redirect: https://grafana.com/docs/k6/latest/examples/http2/ --- If the target system indicates that a connection can be upgraded from HTTP/1.1 to HTTP/2, k6 will do so automatically. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/13 websockets.md b/src/data/markdown/docs/05 Examples/01 Examples/13 websockets.md index 48e7257709..0c1c41de29 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/13 websockets.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/13 websockets.md @@ -3,7 +3,6 @@ title: 'WebSockets' excerpt: | Scripting example on how to use WebSocket API in k6. canonicalUrl: https://grafana.com/docs/k6/latest/examples/websockets/ -redirect: https://grafana.com/docs/k6/latest/examples/websockets/ --- Here's a load test for CrocoChat - a WebSocket chat API available on [https://test-api.k6.io/](https://test-api.k6.io/). diff --git a/src/data/markdown/docs/05 Examples/01 Examples/14 soap.md b/src/data/markdown/docs/05 Examples/01 Examples/14 soap.md index 43bdf8157a..7d1a58a2c3 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/14 soap.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/14 soap.md @@ -2,7 +2,6 @@ title: 'SOAP' excerpt: 'Load Testing SOAP API.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/soap/ -redirect: https://grafana.com/docs/k6/latest/examples/soap/ --- Although k6 doesn't have any built-in APIs for working with SOAP or XML data in general, you diff --git a/src/data/markdown/docs/05 Examples/01 Examples/15 tls.md b/src/data/markdown/docs/05 Examples/01 Examples/15 tls.md index 7c9bb0018f..50166760e6 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/15 tls.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/15 tls.md @@ -4,7 +4,6 @@ excerpt: | TLS is the mechanism through which encrypted connections can be established between clients and servers on the web and through which data can flow with integrity intact. canonicalUrl: https://grafana.com/docs/k6/latest/examples/tls/ -redirect: https://grafana.com/docs/k6/latest/examples/tls/ --- diff --git a/src/data/markdown/docs/05 Examples/01 Examples/19 functional testing.md b/src/data/markdown/docs/05 Examples/01 Examples/19 functional testing.md index ae446c3c43..065d4fc48b 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/19 functional testing.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/19 functional testing.md @@ -3,7 +3,6 @@ title: 'Functional testing' excerpt: | Use Chaijs library for functional and integration testing. canonicalUrl: https://grafana.com/docs/k6/latest/examples/functional-testing/ -redirect: https://grafana.com/docs/k6/latest/examples/functional-testing/ --- ### Most basic integration test diff --git a/src/data/markdown/docs/05 Examples/01 Examples/20 tracking-data-per-url.md b/src/data/markdown/docs/05 Examples/01 Examples/20 tracking-data-per-url.md index 60d813ec11..cda0bee6bd 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/20 tracking-data-per-url.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/20 tracking-data-per-url.md @@ -2,7 +2,6 @@ title: 'Track transmitted data per URL' excerpt: 'This example shows how to track data sent and received for a individual URL.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/track-transmitted-data-per-url/ -redirect: https://grafana.com/docs/k6/latest/examples/track-transmitted-data-per-url/ --- By default, k6 collects automatically two [built-in metrics](/using-k6/metrics#built-in-metrics) related to the transmitted data during the test execution: diff --git a/src/data/markdown/docs/05 Examples/01 Examples/21 URL query parameters.md b/src/data/markdown/docs/05 Examples/01 Examples/21 URL query parameters.md index 3437a76506..c7573eb464 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/21 URL query parameters.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/21 URL query parameters.md @@ -2,7 +2,6 @@ title: 'URLs with query parameters' excerpt: 'Scripting examples using URL and URLSearchParams modules.' canonicalUrl: https://grafana.com/docs/k6/latest/examples/url-query-parameters/ -redirect: https://grafana.com/docs/k6/latest/examples/url-query-parameters/ --- How to use **URL** and **URLSearchParams** imported from [jslib.k6.io](/using-k6/modules#the-jslib-repository) to construct URLs with/without query parameters. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/22 instant-load-increase.md b/src/data/markdown/docs/05 Examples/01 Examples/22 instant-load-increase.md index bdd28fa9a2..4a778c42dc 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/22 instant-load-increase.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/22 instant-load-increase.md @@ -3,7 +3,6 @@ title: 'Instant load increase' excerpt: 'Scripting example on how to instantly increase the number of VUs or iterations and hold them for a period of time' draft: 'false' canonicalUrl: https://grafana.com/docs/k6/latest/examples/instant-load-increase/ -redirect: https://grafana.com/docs/k6/latest/examples/instant-load-increase/ --- One of the common usages of load testing tools it's the so-called stepped arrival rate. diff --git a/src/data/markdown/docs/05 Examples/01 Examples/23 get-timings-for-an-http-metric.md b/src/data/markdown/docs/05 Examples/01 Examples/23 get-timings-for-an-http-metric.md index 09127ec23d..8ceb6208c7 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/23 get-timings-for-an-http-metric.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/23 get-timings-for-an-http-metric.md @@ -2,7 +2,6 @@ title: Get timings for an HTTP metric excerpt: How to calculate timings for an individual k6 metric canonicalUrl: https://grafana.com/docs/k6/latest/examples/get-timings-for-an-http-metric/ -redirect: https://grafana.com/docs/k6/latest/examples/get-timings-for-an-http-metric/ --- diff --git a/src/data/markdown/docs/05 Examples/01 Examples/24 distribute-workloads.md b/src/data/markdown/docs/05 Examples/01 Examples/24 distribute-workloads.md index 8283f4e02d..79b9846112 100644 --- a/src/data/markdown/docs/05 Examples/01 Examples/24 distribute-workloads.md +++ b/src/data/markdown/docs/05 Examples/01 Examples/24 distribute-workloads.md @@ -3,7 +3,6 @@ title: Distribute workloads across VUs excerpt: How to configure different amounts of traffic for different VU behaviors slug: /examples/distribute-workloads canonicalUrl: https://grafana.com/docs/k6/latest/examples/distribute-workloads/ -redirect: https://grafana.com/docs/k6/latest/examples/distribute-workloads/ --- k6 can schedule different load patterns for different VU functions. diff --git a/src/data/markdown/docs/05 Examples/02 Tutorials.md b/src/data/markdown/docs/05 Examples/02 Tutorials.md index 5e0b274046..9b4826081a 100644 --- a/src/data/markdown/docs/05 Examples/02 Tutorials.md +++ b/src/data/markdown/docs/05 Examples/02 Tutorials.md @@ -2,7 +2,6 @@ title: 'Tutorials' excerpt: 'k6 Tutorials' canonicalUrl: https://grafana.com/docs/k6/latest/examples/tutorials/ -redirect: https://grafana.com/docs/k6/latest/examples/tutorials/ --- - [Get started with k6](/examples/tutorials/get-started-with-k6/) diff --git a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6.md b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6.md index 2b54ad380d..f6f1fc4d2b 100644 --- a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6.md +++ b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6.md @@ -2,7 +2,6 @@ title: 'Get started with k6' excerpt: A series of docs to learn how to use the major features of k6 canonicalUrl: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/ -redirect: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/ --- This tutorial provides some procedures for common real-life uses of k6. diff --git a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/100 Test-for-functional-behavior.md b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/100 Test-for-functional-behavior.md index fb5190514f..4a91d4bb2e 100644 --- a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/100 Test-for-functional-behavior.md +++ b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/100 Test-for-functional-behavior.md @@ -2,7 +2,6 @@ title: Test for functional behavior excerpt: Use k6 to write requests and assert that they respond correctly canonicalUrl: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/test-for-functional-behavior/ -redirect: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/test-for-functional-behavior/ --- In this tutorial, learn how to write a test that does the following: diff --git a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/200 Test for performance.md b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/200 Test for performance.md index 82e52fa626..bafadb17dd 100644 --- a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/200 Test for performance.md +++ b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/200 Test for performance.md @@ -2,7 +2,6 @@ title: Test for performance excerpt: Write thresholds to evaluate performance criteria, then increase load to see how the system performs. canonicalUrl: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/test-for-performance/ -redirect: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/test-for-performance/ --- In the previous section, you made a working script to test an endpoint functionality. diff --git a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/300 Analyze results.md b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/300 Analyze results.md index 2c6509fc17..0e7d1251c6 100644 --- a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/300 Analyze results.md +++ b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/300 Analyze results.md @@ -2,7 +2,6 @@ title: Analyze results excerpt: Use k6 to write custom metrics and filter results. canonicalUrl: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/analyze-results/ -redirect: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/analyze-results/ --- In this tutorial, learn how to: diff --git a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/400 Reuse and re-run tests.md b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/400 Reuse and re-run tests.md index 856ba36a4e..f1d2812fbd 100644 --- a/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/400 Reuse and re-run tests.md +++ b/src/data/markdown/docs/05 Examples/02 Tutorials/01 Get started with k6/400 Reuse and re-run tests.md @@ -2,7 +2,6 @@ title: Reuse and re-run tests excerpt: Modularize your k6 test logic and workload configuration. canonicalUrl: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/reuse-and-re-run-tests/ -redirect: https://grafana.com/docs/k6/latest/examples/get-started-with-k6/reuse-and-re-run-tests/ --- In the previous tutorials, you designed k6 scripts to assert performance and make comparing results easy. diff --git a/src/data/markdown/docs/07 extensions/01 Get started/01 Overview.md b/src/data/markdown/docs/07 extensions/01 Get started/01 Overview.md new file mode 100644 index 0000000000..39c929b8a7 --- /dev/null +++ b/src/data/markdown/docs/07 extensions/01 Get started/01 Overview.md @@ -0,0 +1,4 @@ +--- +title: 'Overview' +slug: '/extensions/' +--- diff --git a/src/data/markdown/docs/07 extensions/01 Get started/02 Explore.md b/src/data/markdown/docs/07 extensions/01 Get started/02 Explore.md new file mode 100644 index 0000000000..3a7282bf9c --- /dev/null +++ b/src/data/markdown/docs/07 extensions/01 Get started/02 Explore.md @@ -0,0 +1,4 @@ +--- +title: 'Explore' +slug: '/extensions/get-started/explore' +--- diff --git a/src/data/markdown/docs/07 extensions/01 Get started/03 Build Bundle.md b/src/data/markdown/docs/07 extensions/01 Get started/03 Build Bundle.md new file mode 100644 index 0000000000..7c19b81532 --- /dev/null +++ b/src/data/markdown/docs/07 extensions/01 Get started/03 Build Bundle.md @@ -0,0 +1,4 @@ +--- +title: 'Bundle' +slug: '/extensions/get-started/bundle/' +--- diff --git a/src/data/markdown/docs/07 extensions/01 Get started/04 Create.md b/src/data/markdown/docs/07 extensions/01 Get started/04 Create.md index 249d468a3c..2d73262089 100644 --- a/src/data/markdown/docs/07 extensions/01 Get started/04 Create.md +++ b/src/data/markdown/docs/07 extensions/01 Get started/04 Create.md @@ -2,7 +2,6 @@ title: 'Create' excerpt: 'Creating k6 extensions does not have to be a daunting task, but there are some prerequisites to succeed.' canonicalUrl: https://grafana.com/docs/k6/latest/extensions/create/ -redirect: https://grafana.com/docs/k6/latest/extensions/create/ --- If you find a gap in your testing process that no k6 extension can fix, diff --git a/src/data/markdown/docs/07 extensions/01 Get started/04 Create/01 JavaScript Extensions.md b/src/data/markdown/docs/07 extensions/01 Get started/04 Create/01 JavaScript Extensions.md new file mode 100644 index 0000000000..0cfd7fe515 --- /dev/null +++ b/src/data/markdown/docs/07 extensions/01 Get started/04 Create/01 JavaScript Extensions.md @@ -0,0 +1,348 @@ +--- +title: 'JavaScript Extensions' +excerpt: 'Follow these steps to build a JS extension for k6.' +canonicalUrl: https://grafana.com/docs/k6/latest/extensions/create/javascript-extensions/ +--- + +Take advantage of Go's speed, power, and efficiency while providing the flexibility of using JavaScript APIs +within your test scripts. + +By implementing k6 interfaces, you can close various gaps in your testing setup: + +* New network protocols +* Improved performance +* Features not supported by k6 core + +## Before you start + +To run this tutorial, you'll need the following applications installed: +- Go +- Git + +You also need to install xk6: + +```bash +$ go install go.k6.io/xk6/cmd/xk6@latest +``` + +## Write a simple extension + +1. First, set up a directory to work in: + + ```bash + $ mkdir xk6-compare; cd xk6-compare; go mod init xk6-compare + ``` + +1. In the directory, make a Go file for your JavaScript extension. + + A simple JavaScript extension requires a struct that exposes methods called by the test script. + + + + ```go + package compare + + import "fmt" + + // Compare is the type for our custom API. + type Compare struct{ + ComparisonResult string // textual description of the most recent comparison + } + + // IsGreater returns true if a is greater than b, or false otherwise, setting textual result message. + func (c *Compare) IsGreater(a, b int) bool { + if a > b { + c.ComparisonResult = fmt.Sprintf("%d is greater than %d", a, b) + return true + } else { + c.ComparisonResult = fmt.Sprintf("%d is NOT greater than %d", a, b) + return false + } + } + ``` + +1. Register the module to use these from k6 test scripts. + +
+ + k6 extensions must have the `k6/x/` prefix, + and the short name must be unique among all extensions built in the same k6 binary. + +
+ + ```go + import "go.k6.io/k6/js/modules" + + // init is called by the Go runtime at application startup. + func init() { + modules.Register("k6/x/compare", new(Compare)) + } + ``` + +1. Save the file as something like `compare.go`. The final code looks like this: + + + + ```go + package compare + + import ( + "fmt" + "go.k6.io/k6/js/modules" + ) + + // init is called by the Go runtime at application startup. + func init() { + modules.Register("k6/x/compare", new(Compare)) + } + + // Compare is the type for our custom API. + type Compare struct{ + ComparisonResult string // textual description of the most recent comparison + } + + // IsGreater returns true if a is greater than b, or false otherwise, setting textual result message. + func (c *Compare) IsGreater(a, b int) bool { + if a > b { + c.ComparisonResult = fmt.Sprintf("%d is greater than %d", a, b) + return true + } else { + c.ComparisonResult = fmt.Sprintf("%d is NOT greater than %d", a, b) + return false + } + } + ``` + + + +## Compile your extended k6 + +To build a k6 binary with this extension, run this command: + +```bash +$ xk6 build --with xk6-compare=. +``` + +
+ +When building from source code, `xk6-compare` is the Go module name passed to `go mod init`. +Usually, this would be a URL similar to `github.com/grafana/xk6-compare`. + +
+ + +## Use your extension + +Now, use the extension in a test script! + +1. Make a file with a name like `test.js` then add this code: + + + + ```javascript + import compare from 'k6/x/compare'; + + export default function () { + console.log(`${compare.isGreater(2, 1)}, ${compare.comparison_result}`); + console.log(`${compare.isGreater(1, 3)}, ${compare.comparison_result}`); + } + ``` + + + +1. Run the test with `./k6 run test.js`. + + It should output the following: + + ```shell + INFO[0000] true, 2 is greater than 1 source=console + INFO[0000] false, 1 is NOT greater than 3 source=console + ``` + +## Use the advanced module API + +Suppose your extension needs access to internal k6 objects to, for example, inspect the state of the test during execution. +We will need to make slightly more complicated changes to the above example. + +Our main `Compare` struct should implement the [`modules.Instance`](https://pkg.go.dev/go.k6.io/k6/js/modules#Instance) interface +to access the [`modules.VU`](https://pkg.go.dev/go.k6.io/k6/js/modules#VU) to inspect internal k6 objects such as: + +* [`lib.State`](https://pkg.go.dev/go.k6.io/k6/lib#State), the VU state with values like the VU ID and iteration number +* [`goja.Runtime`](https://pkg.go.dev/github.com/dop251/goja#Runtime), the JavaScript runtime used by the VU +* a global `context.Context` containing objects like the [`lib.ExecutionState`](https://pkg.go.dev/go.k6.io/k6/lib#ExecutionState) + +Additionally, there should be a root module implementation of the [`modules.Module`](https://pkg.go.dev/go.k6.io/k6/js/modules#Module) +interface to serve as a factory of `Compare` instances for each VU. + +
+ +The significance depends on the size of your module. + +
+ + +Here's what that would look like: + + + +```go +package compare + +import ( + "fmt" + "go.k6.io/k6/js/modules" +) + +// init is called by the Go runtime at application startup. +func init() { + modules.Register("k6/x/compare", New()) +} + +type ( + // RootModule is the global module instance that will create module + // instances for each VU. + RootModule struct{} + + // ModuleInstance represents an instance of the JS module. + ModuleInstance struct { + // vu provides methods for accessing internal k6 objects for a VU + vu modules.VU + // comparator is the exported type + comparator *Compare + } +) + +// Ensure the interfaces are implemented correctly. +var ( + _ modules.Instance = &ModuleInstance{} + _ modules.Module = &RootModule{} +) + +// New returns a pointer to a new RootModule instance. +func New() *RootModule { + return &RootModule{} +} + +// NewModuleInstance implements the modules.Module interface returning a new instance for each VU. +func (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance { + return &ModuleInstance{ + vu: vu, + comparator: &Compare{vu: vu}, + } +} + +// Compare is the type for our custom API. +type Compare struct{ + vu modules.VU // provides methods for accessing internal k6 objects + ComparisonResult string // textual description of the most recent comparison +} + +// IsGreater returns true if a is greater than b, or false otherwise, setting textual result message. +func (c *Compare) IsGreater(a, b int) bool { + if a > b { + c.ComparisonResult = fmt.Sprintf("%d is greater than %d", a, b) + return true + } else { + c.ComparisonResult = fmt.Sprintf("%d is NOT greater than %d", a, b) + return false + } +} + +// Exports implements the modules.Instance interface and returns the exported types for the JS module. +func (mi *ModuleInstance) Exports() modules.Exports { + return modules.Exports{ + Default: mi.comparator, + } +} +``` + + + +
+ +Notice that we implemented the Module API and now `modules.Register` the _root module_ rather than our _Compare_ object! + +
+ + +## Accessing runtime state + +At this time, we've provided access to the [`modules.VU`](https://pkg.go.dev/go.k6.io/k6/js/modules#VU) from the `Compare` +type; however, we aren't taking advantage of the methods provided. Here is a contrived example of how we can utilize the +runtime state: + + + +```go +// InternalState holds basic metadata from the runtime state. +type InternalState struct { + ActiveVUs int64 `js:"activeVUs"` + Iteration int64 + VUID uint64 `js:"vuID"` + VUIDFromRuntime goja.Value `js:"vuIDFromRuntime"` +} + +// GetInternalState interrogates the current virtual user for state information. +func (c *Compare) GetInternalState() *InternalState { + state := c.vu.State() + ctx := c.vu.Context() + es := lib.GetExecutionState(ctx) + rt := c.vu.Runtime() + + return &InternalState{ + VUID: state.VUID, + VUIDFromRuntime: rt.Get("__VU"), + Iteration: state.Iteration, + ActiveVUs: es.GetCurrentlyActiveVUsCount(), + } +} +``` + + + +Create a test script to utilize the new `getInternalState()` function as in the following: + + + +```javascript +import compare from 'k6/x/compare'; + +export default function () { + const state = compare.getInternalState(); + console.log( + `Active VUs: ${state.activeVUs}, Iteration: ${state.iteration}, VU ID: ${state.vuID}, VU ID from runtime: ${state.vuIDFromRuntime}` + ); +} +``` + + + +Executing the script as `./k6 run test-state.js --vus 2 --iterations 5` will produce output similar to the following: +```shell +INFO[0000] Active VUs: 2, Iteration: 0, VU ID: 2, VU ID from runtime: 2 source=console +INFO[0000] Active VUs: 2, Iteration: 0, VU ID: 1, VU ID from runtime: 1 source=console +INFO[0000] Active VUs: 2, Iteration: 1, VU ID: 2, VU ID from runtime: 2 source=console +INFO[0000] Active VUs: 2, Iteration: 1, VU ID: 1, VU ID from runtime: 1 source=console +INFO[0000] Active VUs: 2, Iteration: 2, VU ID: 2, VU ID from runtime: 2 source=console +``` + +> For a more extensive usage example of this API, look at the +> [`k6/execution`](https://github.com/grafana/k6/blob/master/js/modules/k6/execution/execution.go) module. + +## Things to keep in mind + +- The code in the `default` function (or another function specified by + [`exec`](/using-k6/scenarios/#options)) will be executed many + times during a test run and possibly in parallel by thousands of VUs. + Any operation of your extension should therefore be performant + and [thread-safe](https://en.wikipedia.org/wiki/Thread_safety). +- Any _heavy_ initialization should be done in the [init context](/javascript-api/init-context/), + if possible, and not as part of the `default` function execution. +- Use the registry's [`NewMetric`](https://pkg.go.dev/go.k6.io/k6/metrics#Registry.NewMetric) method to create + custom metrics; to emit them, use [`metrics.PushIfNotDone()`](https://pkg.go.dev/go.k6.io/k6/metrics#PushIfNotDone). + +> Questions? Feel free to join the discussion on extensions in the [k6 Community Forum](https://community.grafana.com/c/grafana-k6/extensions/82). + +Next, create an [Output extension](/extensions/get-started/create/output-extensions/) to publish test metrics +to a destination not already supported by k6. + diff --git a/src/data/markdown/docs/07 extensions/01 Get started/04 Create/02 Output Extensions.md b/src/data/markdown/docs/07 extensions/01 Get started/04 Create/02 Output Extensions.md new file mode 100644 index 0000000000..4ce5ab33cb --- /dev/null +++ b/src/data/markdown/docs/07 extensions/01 Get started/04 Create/02 Output Extensions.md @@ -0,0 +1,247 @@ +--- +title: 'Output Extensions' +excerpt: 'Follow these steps to build an output extension for k6.' +canonicalUrl: https://grafana.com/docs/k6/latest/extensions/create/output-extensions/ +--- + +k6 provides many [metrics](/using-k6/metrics) and [output formats](/results-output/overview/), but it cannot directly support all possibilities. +To store or alter metrics captured during an active k6 test, +you can create a custom output extension. + +Output extension binaries can use the `--out` flag to send metrics to a custom place. +Some potential reasons for a custom extension could include: +* To support a time-series database not already supported +* To add derived metrics data for storage +* To filter metrics to only the data you care about + +Like [JavaScript extensions](/extensions/get-started/create/javascript-extensions/), +output extensions rely on the extension author to implement specific APIs. + +## Before you start: + +To run this tutorial, you'll need the following applications installed: +- Go +- Git + +You also need to install xk6: + +```bash +$ go install go.k6.io/xk6/cmd/xk6@latest +``` + +## Write a simple extension + +1. Set up a directory to work in. + + ```bash + $ mkdir xk6-output-logger; cd xk6-output-logger; go mod init xk6-output-logger + ``` + +1. The core of an Output extension is a struct that implements the [`output.Output`](https://pkg.go.dev/go.k6.io/k6/output#Output) +interface. + + Create a simple example that outputs each set of metrics to the console as received by the `AddMetricSamples(samples []metrics.SampleContainer)` +method of the output interface. + + ```go + package log + + import ( + "fmt" + "strings" + "time" + + "go.k6.io/k6/metrics" + "go.k6.io/k6/output" + ) + + // AddMetricSamples receives metric samples from the k6 Engine as they're emitted. + func (l *Logger) AddMetricSamples(samples []metrics.SampleContainer) { + for _, sample := range samples { + all := sample.GetSamples() + fmt.Fprintf(l.out, "%s [%s]\n", all[0].GetTime().Format(time.RFC3339Nano), metricKeyValues(all)) + } + } + + // metricKeyValues returns a string of key-value pairs for all metrics in the sample. + func metricKeyValues(samples []metrics.Sample) string { + names := make([]string, 0, len(samples)) + for _, sample := range samples { + names = append(names, fmt.Sprintf("%s=%v", sample.Metric.Name, sample.Value)) + } + return strings.Join(names, ", ") + } + ``` + +1. Register the module to use these from k6 test scripts. + + ```go + import "go.k6.io/k6/output" + + // init is called by the Go runtime at application startup. + func init() { + output.RegisterExtension("logger", New) + } + ``` + +
+ +You must use the registered with the `-o`, or `--out` flag when running k6! + +
+ +The final extension code looks like this: + + + +```go +package log + +import ( + "fmt" + "io" + "strings" + "time" + + "go.k6.io/k6/metrics" + "go.k6.io/k6/output" +) + +// init is called by the Go runtime at application startup. +func init() { + output.RegisterExtension("logger", New) +} + +// Logger writes k6 metric samples to stdout. +type Logger struct { + out io.Writer +} + +// New returns a new instance of Logger. +func New(params output.Params) (output.Output, error) { + return &Logger{params.StdOut}, nil +} + +// Description returns a short human-readable description of the output. +func (*Logger) Description() string { + return "logger" +} + +// Start initializes any state needed for the output, establishes network +// connections, etc. +func (o *Logger) Start() error { + return nil +} + +// AddMetricSamples receives metric samples from the k6 Engine as they're emitted. +func (l *Logger) AddMetricSamples(samples []metrics.SampleContainer) { + for _, sample := range samples { + all := sample.GetSamples() + fmt.Fprintf(l.out, "%s [%s]\n", all[0].GetTime().Format(time.RFC3339Nano), metricKeyValues(all)) + } +} + +// metricKeyValues returns a string of key-value pairs for all metrics in the sample. +func metricKeyValues(samples []metrics.Sample) string { + names := make([]string, 0, len(samples)) + for _, sample := range samples { + names = append(names, fmt.Sprintf("%s=%v", sample.Metric.Name, sample.Value)) + } + return strings.Join(names, ", ") +} + +// Stop finalizes any tasks in progress, closes network connections, etc. +func (*Logger) Stop() error { + return nil +} +``` + + + +Notice a couple of things: + +- The module initializer `New()` receives an instance of + [`output.Params`](https://pkg.go.dev/go.k6.io/k6/output#Params). + With this object, the extension can access the output-specific configuration, + interfaces to the filesystem, synchronized stdout and stderr, and more. + +- `AddMetricSamples` in this example writes to stdout. This output might have + to be buffered and flushed periodically in a real-world scenario to avoid memory + leaks. Below we'll discuss some helpers you can use for that. + +## Compile your extended k6 + +To build a k6 binary with this extension, run: + +```bash +$ xk6 build --with xk6-output-logger=. +``` + +
+ +`xk6-output-logger` is the Go module name passed to `go mod init` + +Usually, this would be a URL similar to `github.com/grafana/xk6-output-logger`. + +
+ + +## Use your extension + +Now we can use the extension with a test script. + +1. In new JavaScript file, make some simple test logic. + + + + ```javascript + import http from 'k6/http'; + import { sleep } from 'k6'; + + export default function () { + http.get('https://test-api.k6.io'); + sleep(0.5); + } + ``` + + + +1. Now, run the test. + + ```bash + $ ./k6 run test.js --out logger --quiet --no-summary --iterations 2 + ``` + +
+ +The `--out logger` argument tells k6 to use your custom output. The flag +`--quiet --no-summary` configures k6 to show only custom output. + +
+ +Your output should look something like this: + +```shell +2022-07-01T08:55:09.59272-05:00 [http_reqs=1, http_req_duration=117.003, http_req_blocked=558.983, http_req_connecting=54.135, http_req_tls_handshaking=477.198, http_req_sending=0.102, http_req_waiting=116.544, http_req_receiving=0.357, http_req_failed=0] +2022-07-01T08:55:09.917036-05:00 [vus=1, vus_max=1] +2022-07-01T08:55:10.094196-05:00 [data_sent=446, data_received=21364, iteration_duration=1177.505083, iterations=1] +2022-07-01T08:55:10.213926-05:00 [http_reqs=1, http_req_duration=119.122, http_req_blocked=0.015, http_req_connecting=0, http_req_tls_handshaking=0, http_req_sending=0.103, http_req_waiting=118.726, http_req_receiving=0.293, http_req_failed=0] +2022-07-01T08:55:10.715323-05:00 [data_sent=102, data_received=15904, iteration_duration=620.862459, iterations=1] +``` + +## Things to keep in mind + +- Output structs can optionally implement additional interfaces that allow them to + receive [thresholds](https://pkg.go.dev/go.k6.io/k6/output#WithThresholds) or + [run-status updates](https://pkg.go.dev/go.k6.io/k6/output#WithRunStatusUpdates) + and even [interrupt a test](https://pkg.go.dev/go.k6.io/k6/output#WithTestRunStop). +- Consider using [`output.SampleBuffer`](https://pkg.go.dev/go.k6.io/k6/output#SampleBuffer) + and [`output.PeriodicFlusher`](https://pkg.go.dev/go.k6.io/k6/output#PeriodicFlusher) + to improve performance given the large amounts of data produced by k6. Refer to + [`statsd` output](https://github.com/grafana/k6/blob/master/output/statsd/output.go) for an example. +- Use the [project template](https://github.com/grafana/xk6-output-template) as a starting point + for your output extension. + +> Questions? Feel free to join the discussion on extensions in the [k6 Community Forum](https://community.grafana.com/c/grafana-k6/extensions/82). + diff --git a/src/data/markdown/docs/07 extensions/02 Explanations/010-extensions-registry.md b/src/data/markdown/docs/07 extensions/02 Explanations/010-extensions-registry.md index 5b776c4319..76480bb7a9 100644 --- a/src/data/markdown/docs/07 extensions/02 Explanations/010-extensions-registry.md +++ b/src/data/markdown/docs/07 extensions/02 Explanations/010-extensions-registry.md @@ -3,7 +3,6 @@ title: About the Extensions Registry excerpt: Reasons for the registry and what is required to be included. hideFromSidebar: false canonicalUrl: https://grafana.com/docs/k6/latest/extensions/explanations/extensions-registry/ -redirect: https://grafana.com/docs/k6/latest/extensions/explanations/extensions-registry/ --- Did you create an extension and want to share it with your fellow k6 users? diff --git a/src/data/markdown/docs/07 extensions/02 Explanations/020-go-js-bridge.md b/src/data/markdown/docs/07 extensions/02 Explanations/020-go-js-bridge.md index 028de089dc..5acceee621 100644 --- a/src/data/markdown/docs/07 extensions/02 Explanations/020-go-js-bridge.md +++ b/src/data/markdown/docs/07 extensions/02 Explanations/020-go-js-bridge.md @@ -3,7 +3,6 @@ title: About the Go-to-JS bridge excerpt: Technical details about how JavaScript works in the goja engine. slug: /extensions/explanations/go-js-bridge canonicalUrl: https://grafana.com/docs/k6/latest/extensions/explanations/go-js-bridge/ -redirect: https://grafana.com/docs/k6/latest/extensions/explanations/go-js-bridge/ --- All k6 and xk6 binaries have an embedded JavaScript engine, [goja](https://github.com/dop251/goja), diff --git a/src/data/markdown/docs/07 extensions/02 Explanations/030-extension-graduation.md b/src/data/markdown/docs/07 extensions/02 Explanations/030-extension-graduation.md index 3af5da1e9c..cccf9f4728 100644 --- a/src/data/markdown/docs/07 extensions/02 Explanations/030-extension-graduation.md +++ b/src/data/markdown/docs/07 extensions/02 Explanations/030-extension-graduation.md @@ -3,7 +3,6 @@ title: Extension Graduation excerpt: Some extensions are created with the intent to become a part of core of k6. hideFromSidebar: false canonicalUrl: https://grafana.com/docs/k6/latest/extensions/explanations/extension-graduation/ -redirect: https://grafana.com/docs/k6/latest/extensions/explanations/extension-graduation/ --- Some _Go_ extensions may one day be available within the k6 binary. diff --git a/src/data/markdown/docs/07 extensions/03 Guides/02 bundling.md b/src/data/markdown/docs/07 extensions/03 Guides/02 bundling.md index 7cc7ae2c43..7997ae68ee 100644 --- a/src/data/markdown/docs/07 extensions/03 Guides/02 bundling.md +++ b/src/data/markdown/docs/07 extensions/03 Guides/02 bundling.md @@ -2,7 +2,6 @@ title: 'Build a k6 binary using Go' excerpt: 'Guide to build a k6 binary that includes one or many extensions using xk6.' canonicalUrl: https://grafana.com/docs/k6/latest/extensions/build-k6-binary-using-go/ -redirect: https://grafana.com/docs/k6/latest/extensions/build-k6-binary-using-go/ --- To use an extension that you found on the [Extension page](/extensions/get-started/explore/) or the [xk6 GitHub topic](https://github.com/topics/xk6), diff --git a/src/data/markdown/docs/07 extensions/03 Guides/build-k6-using-docker.md b/src/data/markdown/docs/07 extensions/03 Guides/build-k6-using-docker.md index 960200b78b..5258e2cfcd 100644 --- a/src/data/markdown/docs/07 extensions/03 Guides/build-k6-using-docker.md +++ b/src/data/markdown/docs/07 extensions/03 Guides/build-k6-using-docker.md @@ -3,7 +3,6 @@ title: 'Build a k6 binary using Docker' excerpt: '' hideFromSidebar: false canonicalUrl: https://grafana.com/docs/k6/latest/extensions/build-k6-binary-using-docker/ -redirect: https://grafana.com/docs/k6/latest/extensions/build-k6-binary-using-docker/ --- Using the [xk6 Docker image](https://hub.docker.com/r/grafana/xk6/) can simplify the process of creating a custom k6 binary. It avoids having to setup a local Go environment, and install xk6 manually. diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws.md new file mode 100755 index 0000000000..09b4a1d73d --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws.md @@ -0,0 +1,45 @@ +--- +title: "aws" +excerpt: "aws is a library implementing APIs for accessing a selection of AWS services" +description: "aws is a library implementing APIs for accessing a selection of AWS servicese" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/ +--- + +The `aws` module is a JavaScript library that wraps around some Amazon AWS services API. + +The library exposes a couple of configuration and client classes allowing to interact with a subset of AWS services in the context of k6 load test scripts: +- [EventBridge](/javascript-api/jslib/aws/eventbridgeclient): a class to send custom events to Amazon EventBridge. +- [KMSClient](/javascript-api/jslib/aws/kmsclient): a class to list and generate keys from the AWS Key Management Service. +- [S3Client](/javascript-api/jslib/aws/s3client): a class to list S3 buckets and the objects they contain, as well as uploading, downloading and deleting objects from them. +- [SecretsManagerClient](/javascript-api/jslib/aws/secretsmanagerclient): a class to list, get, create, update, and delete secrets from the AWS secrets manager service. +- [SQSClient](/javascript-api/jslib/aws/sqsclient): a class to list and send messages to SQS queues. +- [SystemsManagerClient](/javascript-api/jslib/aws/systemsmanagerclient): a class to fetch parameters from the AWS Systems Manager Service. +- [SignatureV4](/javascript-api/jslib/aws/signaturev4): a class to sign and pre-sign requests to AWS services using the [Signature V4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) algorithm. +- [AWSConfig](/javascript-api/jslib/aws/awsconfig/): a class is used by each client classes to provide them access to AWS credentials as well as configuration. + +> ⭐️ Source code available on [GitHub](https://github.com/grafana/k6-jslib-aws). +> Please request features and report bugs through [GitHub issues](https://github.com/grafana/k6-jslib-aws/issues). + + +
+ +#### This library is in active development + +This library is stable enough to be useful, but pay attention to the new versions released on [jslib.k6.io](https://jslib.k6.io) and [k6-jslib-aws/releases](https://github.com/grafana/k6-jslib-aws/releases). + +This documentation is for the last version only. If you discover that some code below does not work, it most likely means that you are using an older version. + +
+ +### Classes + +| Library | Description | +| :--------------------------------------------------------------------- | :------------------------------------------------------------------- | +| [AWSConfig](/javascript-api/jslib/aws/awsconfig) | Class to configure AWS client classes. | +| [EventBridge](/javascript-api/jslib/aws/eventbridgeclient) | Client class to interact with AWS EventBridge service. | +| [KMSClient](/javascript-api/jslib/aws/kmsclient) | Client class to interact with AWS Key Management Service. | +| [S3Client](/javascript-api/jslib/aws/s3client) | Client class to interact with AWS S3 buckets and objects. | +| [SecretsManager](/javascript-api/jslib/aws/secretsmanagerclient) | Client class to interact with AWS secrets stored in Secrets Manager. | +| [SignatureV4](/javascript-api/jslib/aws/signaturev4) | Class to sign and pre-sign requests to AWS services. | +| [SQSClient](/javascript-api/jslib/aws/sqsclient) | Client class to interact with AWS Simple Queue Service. | +| [SystemsManagerClient](/javascript-api/jslib/aws/systemsmanagerclient) | Client class to interact with AWS Systems Manager Service. | \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 AwsConfig.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 AwsConfig.md new file mode 100755 index 0000000000..a7e4f46834 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 AwsConfig.md @@ -0,0 +1,64 @@ +--- +title: 'AWSConfig' +head_title: 'AWSConfig' +description: 'AWSConfig is used to configure an AWS service client instances' +excerpt: 'AWSConfig is used to configure an AWS service client instances' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/awsconfig/ +--- + +AWSConfig is used to configure an AWS service client instance, such as [S3Client](/javascript-api/jslib/aws/s3client) or [SecretsManagerClient](/javascript-api/jslib/aws/secretsmanagerclient). It effectively allows the user to select a [region](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html) they wish to interact with, and the AWS credentials they wish to use to authenticate. + +AWSConfig is included in the `aws.js` bundle, which includes all the content of the library. It is also included in the various services clients dedicated bundles such as `s3.js` and `secrets-manager.js`. + +It takes an options object as its single parameter, with the following properties: + +| Property | Type | Description | +| :------------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------ | +| region | string | the AWS region to connect to. As described by [Amazon AWS docs](https://docs.aws.amazon.com/general/latest/gr/rande.html) | +| accessKeyID | string | The AWS access key ID credential to use for authentication. | +| secretAccessKey | string | The AWS secret access credential to use for authentication. | +| sessionToken (optional) | string | The AWS secret access token to use for authentication. | + +### Methods + +| Name | Description | +| :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------- | +| `fromEnvironment()` | Creates an `AWSConfig` using the `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_SESSION_TOKEN` environment variables. | + +### Throws + +S3 Client methods will throw errors in case of failure. + +| Error | Condition | +| :------------------------- | :--------------------------------------------------------- | +| InvalidArgumentException | when an invalid region name or credentials were used. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +// Note that you AWSConfig is also included in the dedicated service +// client bundles such as `s3.js` and `secrets-manager.js` +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/aws.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); + +export default function () { + // ... +} +``` + +_k6 will instantiate an `AWSConfig` object and use it to configure a `SecretsManagerClient` instance_ + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 EventBridgeClient.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 EventBridgeClient.md new file mode 100644 index 0000000000..c96904cf4e --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 EventBridgeClient.md @@ -0,0 +1,66 @@ +--- +title: 'EventBridgeClient' +head_title: 'EventBridgeClient' +description: 'EventBridgeClient allows interacting with AWS EventBridge service' +excerpt: 'EventBridgeClient class allows sending custom events to Amazon EventBridge so that they can be matched to rules.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/eventbridgeclient/ +--- + +`EventBridgeClient` interacts with the AWS EventBridge service. + +With it, you can send custom events to Amazon EventBridge. These events can then be matched to rules defined in EventBridge. For a full list of supported operations, see [Methods](#methods). + +Both the dedicated `event-bridge.js` jslib bundle and the all-encompassing `aws.js` bundle include the `EventBridgeClient`. + +### Methods + +| Function | Description | +| :--------------------------------------------------------------------------------------------- | :------------------------------------------------- | +| [putEvents(input)](/javascript-api/jslib/aws/eventbridgeclient/eventbridgeclient-putevents/) | Send custom events to Amazon EventBridge. | + +### Throws + +EventBridgeClient methods will throw errors in case of failure. + +| Error | Condition | +| :----------------------- | :-------------------------------------------------------------------------- | +| InvalidSignatureError | when invalid credentials were provided or the request signature is invalid. | +| EventBridgeServiceError | when AWS replied to the requested operation with an error. | + +### Examples + + + +```javascript +import { AWSConfig, EventBridgeClient } from 'https://jslib.k6.io/aws/0.11.0/event-bridge.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const eventBridge = new EventBridgeClient(awsConfig); + +export default async function () { + const eventDetails = { + Source: 'my.custom.source', + Detail: { key1: 'value1', key2: 'value2' }, + DetailType: 'MyDetailType', + Resources: ['arn:aws:resource1'], + }; + + const input = { + Entries: [eventDetails] + }; + + try { + await eventBridge.putEvents(input); + } catch (error) { + console.error(`Failed to put events: ${error.message}`); + } +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 KMSClient.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 KMSClient.md new file mode 100644 index 0000000000..86bcdac0c0 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 KMSClient.md @@ -0,0 +1,70 @@ +--- +title: 'KMSClient' +head_title: 'KMSClient' +description: 'KMSClient allows interacting with the AWS Key Management Service' +excerpt: 'KMSClient allows interacting with the AWS Key Management Service' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/kmsclient/ +--- + + + +`KMSClient` interacts with the AWS Key Management Service. + +With it, the user can list all the Key Management Service keys in the caller's AWS account and region. They can also generate symmetric data keys to use outside of AWS Key Management Service. + +Both the dedicated `kms.js` jslib bundle and the all-encompassing `aws.js` bundle include the `KMSClient`. + +### Methods + +| Function | Description | +| :-------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------- | +| [listKeys](/javascript-api/jslib/aws/kmsclient/kmsclient-listkeys/) | List the all the Key Management Service keys in the caller's AWS account and region. | +| [generateDataKey](/javascript-api/jslib/aws/kmsclient/kmsclient-generatedatakey/) | Generate a symmetric data key for use outside of the AWS Key Management Service. | + +### Throws + +`KMSClient` methods throw errors in case of failure. + +| Error | Condition | +| :-------------------- | :--------------------------------------------------------- | +| `InvalidSignatureError` | when using invalid credentials | +| `KMSServiceError` | when AWS replied to the requested operation with an error | + +### Example + + + +```javascript +import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js'; + +import { AWSConfig, KMSClient } from 'https://jslib.k6.io/aws/0.11.0/kms.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const kms = new KMSClient(awsConfig); +const keyAlias = 'alias/k6-key'; + +export async function setup() { + // Create a symmetric data key + return { + dataKey: await kms.generateDataKey(keyAlias, 32), + }; +} + +export default async function (data) { + // Use the data key to encrypt data +} + +export function handleSummary(data) { + return { + 'stdout': textSummary(data, { indent: ' ', enableColors: true }), + './test-run.key': data.dataKey, + }; +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 S3Client.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 S3Client.md new file mode 100755 index 0000000000..ce5905cd87 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 S3Client.md @@ -0,0 +1,176 @@ +--- +title: 'S3Client' +head_title: 'S3Client' +description: 'S3Client allows interacting with AWS S3 buckets and objects' +excerpt: 'S3Client class allows interacting with AWS S3 buckets and objects' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/ +--- + + + +`S3Client` interacts with the AWS Simple Storage Service (S3). + +With it, you can do several operations such as list buckets, list objects in a bucket, or download objects from a bucket. For a full list of supported operations, see [Methods](#methods). + +Both the dedicated `s3.js` jslib bundle and the all-encompassing `aws.js` bundle include the `S3Client`. + +### Methods + +| Function | Description | +| :-------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------- | +| [listBuckets()](/javascript-api/jslib/aws/s3client/s3client-listbuckets) | List the buckets the authenticated user has access to | +| [listObjects(bucketName, [prefix])](/javascript-api/jslib/aws/s3client/s3client-listobjects/) | List the objects contained in a bucket | +| [getObject(bucketName, objectKey)](/javascript-api/jslib/aws/s3client/s3client-getobject/) | Download an object from a bucket | +| [putObject(bucketName, objectKey, data)](/javascript-api/jslib/aws/s3client/s3client-putobject/) | Upload an object to a bucket | +| [deleteObject(bucketName, objectKey)](/javascript-api/jslib/aws/s3client/s3client-deleteobject/) | Delete an object from a bucket | +| [copyObject(sourceBucket, sourceKey, destinationBucket, destinationKey)](/javascript-api/jslib/aws/s3client/s3client-copyobject/) | Copy an object from one bucket to another | +| [createMultipartUpload(bucketName, objectKey)](/javascript-api/jslib/aws/s3client/s3client-createmultipartupload/) | Create a multipart upload for a given objectKey to a bucket | +| [uploadPart(bucketName, objectKey, uploadId, partNumber, data)](/javascript-api/jslib/aws/s3client/s3client-uploadpart/) | Upload a part in a multipart upload | +| [completeMultipartUpload(bucketName, objectKey, uploadId, parts)](/javascript-api/jslib/aws/s3client/s3client-completemultipartupload/) | Complete a previously assembled multipart upload | +| [abortMultipartUpload(bucketName, objectKey, uploadId)](/javascript-api/jslib/aws/s3client/s3client-abortmultipartupload/) | Abort a multipart upload | + +### Throws + +S3 Client methods will throw errors in case of failure. + +| Error | Condition | +| :-------------------- | :--------------------------------------------------------- | +| InvalidSignatureError | when invalid credentials were provided. | +| S3ServiceError | when AWS replied to the requested operation with an error. | + +### Examples + + + +```javascript +import { check } from 'k6'; +import exec from 'k6/execution'; +import http from 'k6/http'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testInputFileKey = 'productIDs.json'; +const testOutputFileKey = `results-${Date.now()}.json`; + +export async function setup() { + // If our test bucket does not exist, abort the execution. + const buckets = await s3.listBuckets(); + if (buckets.filter((b) => b.name === testBucketName).length == 0) { + exec.test.abort(); + } + + // If our test object does not exist, abort the execution. + const objects = await s3.listObjects(testBucketName); + if (objects.filter((o) => o.key === testInputFileKey).length == 0) { + exec.test.abort(); + } + + // Download the S3 object containing our test data + const inputObject = await s3.getObject(testBucketName, testInputFileKey); + + // Let's return the downloaded S3 object's data from the + // setup function to allow the default function to use it. + return { + productIDs: JSON.parse(inputObject.data), + }; +} + +export default async function (data) { + // Pick a random product ID from our test data + const randomProductID = data.productIDs[Math.floor(Math.random() * data.productIDs.length)]; + + // Query our ecommerce website's product page using the ID + const res = await http.asyncRequest("GET", `http://your.website.com/product/${randomProductID}/`); + check(res, { 'is status 200': res.status === 200 }); +} + +export async function handleSummary(data) { + // Once the load test is over, let's upload the results to our + // S3 bucket. This is executed after teardown. + await s3.putObject(testBucketName, testOutputFileKey, JSON.stringify(data)); +} +``` + + + +#### Multipart uploads + + + +```javascript +import crypto from 'k6/crypto'; +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // List the buckets the AWS authentication configuration + // gives us access to. + const buckets = await s3.listBuckets(); + + // If our test bucket does not exist, abort the execution. + if (buckets.filter((b) => b.name === testBucketName).length == 0) { + exec.test.abort(); + } + + // Produce random bytes to upload of size ~12MB, that + // we will upload in two 6MB parts. This is done as the + // minimum part size supported by S3 is 5MB. + const bigFile = crypto.randomBytes(12 * 1024 * 1024); + + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + + // Upload the first part + const firstPartData = bigFile.slice(0, 6 * 1024 * 1024); + const firstPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 1, + firstPartData + ); + + // Upload the second part + const secondPartData = bigFile.slice(6 * 1024 * 1024, 12 * 1024 * 1024); + const secondPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 2, + secondPartData + ); + + // Complete the multipart upload + await s3.completeMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId, [ + firstPart, + secondPart, + ]); + + // Let's redownload it verify it's correct, and delete it + const obj = await s3.getObject(testBucketName, testFileKey); + await s3.deleteObject(testBucketName, testFileKey); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SQSClient.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SQSClient.md new file mode 100644 index 0000000000..88b6ae26a2 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SQSClient.md @@ -0,0 +1,62 @@ +--- +title: 'SQSClient' +head_title: 'SQSClient' +description: 'SQSClient enables interaction with the AWS Simple Queue Service (SQS)' +excerpt: 'SQSClient allows interacting with the AWS Simple Queue Service (SQS)' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/sqsclient/ +--- + +`SQSClient` interacts with the AWS Simple Queue Service (SQS). + +With it, the user can send messages to specified queues and list available queues in the current region. + +`SQSClient` is included in both the dedicated `sqs.js` jslib bundle and the all-encompassing `aws.js` one, containing all the services clients. + +### Methods + +| Function | Description | +| :--------------------------------------------------------------- | :--------------------------------------------------- | +| [`sendMessage`](/javascript-api/jslib/aws/sqsclient/sqsclient-sendmessage) | Delivers a message to the specified queue. | +| [`listQueues`](/javascript-api/jslib/aws/sqsclient/sqsclient-listqueues) | Returns a list of your queues in the current region. | + +### Throws + +`SQSClient` methods throw errors in case of failure. + +| Error | Condition | +| :---------------------- | :-------------------------------------------------------- | +| `InvalidSignatureError` | when using invalid credentials | +| `SQSServiceError` | when AWS replied to the requested operation with an error | + +### Example + + + +```javascript +import exec from 'k6/execution' + +import { AWSConfig, SQSClient } from 'https://jslib.k6.io/aws/0.11.0/sqs.js' + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}) + +const sqs = new SQSClient(awsConfig) +const testQueue = 'https://sqs.us-east-1.amazonaws.com/000000000/test-queue' + +export default async function () { + // If our test queue does not exist, abort the execution. + const queuesResponse = await sqs.listQueues() + if (queuesResponse.queueUrls.filter((q) => q === testQueue).length == 0) { + exec.test.abort() + } + + // Send message to test queue + await sqs.sendMessage(testQueue, JSON.stringify({value: '123'})); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SecretsManagerClient.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SecretsManagerClient.md new file mode 100755 index 0000000000..86b6598453 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SecretsManagerClient.md @@ -0,0 +1,91 @@ +--- +title: 'SecretsManagerClient' +head_title: 'SecretsManagerClient' +description: 'SecretsManagerClient allows interacting with AWS secrets stored in Secrets Manager' +excerpt: 'SecretsManagerClient allows interacting with AWS secrets stored in Secrets Manager' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/ +--- + +`SecretsManagerClient` interacts with the AWS Secrets Manager. + +With it, you can perform several operations such as listing, creating and downloading secrets owned by the authenticated user. For a full list of supported operations, see [Methods](#methods). + +`SecretsManagerClient` is included in both the dedicated jslib `secrets-manager.js` bundle, and the `aws.js` one, containing all the services clients. + +### Methods + +| Function | Description | +| :------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------- | +| [listSecrets()](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-listsecrets/) | List secrets owned by the authenticated user | +| [getSecret(secretID)](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-getsecret/) | Download a secret | +| [createSecret(name, secretString, description, [versionID], [tags])](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-createsecret/) | Create a new secret | +| [putSecretValue(secretID, secretString, [versionID])](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-putsecretvalue/) | Update a secret | +| [deleteSecret(secretID, { recoveryWindow: 30, noRecovery: false}})](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-deletesecret/) | Delete a secret | + +### Throws + +S3 Client methods will throw errors in case of failure. + +| Error | Condition | +| :------------------------- | :--------------------------------------------------------- | +| InvalidSignatureError | when invalid credentials were provided. | +| SecretsManagerServiceError | when AWS replied to the requested operation with an error. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; +const testSecretValue = 'jslib-test-value'; + +export async function setup() { + // Let's make sure our test secret is created + const testSecret = await secretsManager.createSecret( + testSecretName, + testSecretValue, + 'this is a test secret, delete me.' + ); + + // List the secrets the AWS authentication configuration + // gives us access to, and verify the creation was successful. + const secrets = await secretsManager.listSecrets(); + if (!secrets.filter((s) => s.name === testSecret.name).length == 0) { + exec.test.abort('test secret not found'); + } +} + +export default async function () { + // Knnowing that we know the secret exist, let's update its value + const newTestSecretValue = 'new-test-value'; + await secretsManager.putSecretValue(testSecretName, newTestSecretValue); + + // Let's get its value and verify it was indeed updated + const updatedSecret = await secretsManager.getSecret(testSecretName); + if (updatedSecret.secret !== newTestSecretValue) { + exec.test.abort('unable to update test secret'); + } + + // Let's now use our secret in the context of our load test... +} + +export async function teardown() { + // Finally, let's clean after ourselves and delete our test secret + await secretsManager.deleteSecret(testSecretName, { noRecovery: true }); +} +``` + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SignatureV4.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SignatureV4.md new file mode 100644 index 0000000000..d13aa7bb3b --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SignatureV4.md @@ -0,0 +1,153 @@ +--- +title: 'SignatureV4' +head_title: 'SignatureV4' +description: 'SignatureV4 is used to sign or pre-sign requests to AWS services using the Signature V4 algorithm' +excerpt: 'SignatureV4 is used to sign and pre-sign requests to AWS services using the Signature V4 algorithm' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/signaturev4/ +--- + + + +With SignatureV4, you can produce authenticated HTTP requests to AWS services. Namely, it lets you sign and pre-sign requests to AWS services using the [Signature V4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) algorithm. The `sign` operation produces a signed request with authorization information stored in its headers. +The `presign` operation produces a pre-signed request with authorization information stored in its query string parameters. + +SignatureV4 is included in both the dedicated jslib `signature.js` bundle and the `aws.js` one, containing all the service's clients. + +Instantiating a new `SignatureV4` requires a single options object argument with the following properties: + +| Property | Type | Description | +| :------------ | :---------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| service | string | the AWS region to sign or pre-sign requests for. As described by [Amazon AWS docs](https://docs.aws.amazon.com/general/latest/gr/rande.html) | +| region | string | the AWS service to sign or pre-sign requests for. As described by [Amazon AWS docs](https://aws.amazon.com/about-aws/global-infrastructure/regions_az/)] | +| credentials | an object with `accessKeyId`, `secretAccessKeyId`, and optional `sessionToken` properties | the AWS credentials to sign or pre-sign requests with. | +| uriEscapePath | boolean | Whether to uri-escape the request URI path as part of computing the canonical request string. As of late 2017, this is **required for every AWS service** except Amazon S3. | +| applyChecksum | boolean | Whether to calculate a checksum of the request body and include it as either a request header (when signing) or as a query string parameter (when pre-signing). This is **required for AWS Glacier and Amazon S3** and optional for every other AWS service as of late 2017. | + +## Methods + + +| Method | Description | +| :--------------------------------------------------------- | :---------------------------------------------------------------------------- | +| [sign()](/javascript-api/jslib/aws/signaturev4/sign) | Signs an authenticated HTTP request using the AWS signature v4 algorithm | +| [presign()](/javascript-api/jslib/aws/signaturev4/presign) | Produces an authenticated pre-signed URL using the AWS signature v4 algorithm | + + +### Throws + +SignatureV4 methods throw errors on failure. + +| Error | Condition | +| :-------------------- | :-------------------------------------- | +| InvalidSignatureError | when invalid credentials were provided. | + +### Example + + + +```javascript +import http from 'k6/http' + +import { AWSConfig, SignatureV4 } from 'https://jslib.k6.io/aws/0.11.0/aws.js' + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}) + +export default function () { + /** + * In order to be able to sign an HTTP request's, + * we need to instantiate a SignatureV4 object. + */ + const signer = new SignatureV4({ + service: 's3', + region: awsConfig.region, + credentials: { + accessKeyId: awsConfig.accessKeyId, + secretAccessKey: awsConfig.secretAccessKey, + sessionToken: awsConfig.sessionToken, + }, + + /** + * Whether the URI should be escaped or not. + */ + uriEscapePath: false, + + /** + * Whether or not the body's hash should be calculated and included + * in the request. + */ + applyChecksum: false, + }) + + /** + * The sign operation will return a new HTTP request with the + * AWS signature v4 protocol headers added. It returns an Object + * implementing the SignedHTTPRequest interface, holding a `url` and a `headers` + * properties, ready to use in the context of k6's http call. + */ + const signedRequest = signer.sign( + /** + * HTTP request description + */ + { + /** + * The HTTP method we will use in the request. + */ + method: 'GET', + + /** + * The network protocol we will use to make the request. + */ + protocol: 'https', + + /** + * The hostname of the service we will be making the request to. + */ + hostname: 'mybucket.s3.us-east-1.amazonaws.com', + + /** + * The path of the request. + */ + path: '/myfile.txt', + + /** + * The headers we will be sending in the request. + */ + headers: {}, + }, + + /** + * (optional) Signature operation options allows to override the + * SignatureV4's options in the context of this specific request. + */ + { + /** + * The date and time to be used as signature metadata. This value should be + * a Date object, a unix (epoch) timestamp, or a string that can be + * understood by the JavaScript `Date` constructor.If not supplied, the + * value returned by `new Date()` will be used. + */ + signingDate: new Date(), + + /** + * The service signing name. It will override the service name of the signer + * in current invocation + */ + signingService: 's3', + + /** + * The region name to sign the request. It will override the signing region of the + * signer in current invocation + */ + signingRegion: 'us-east-1', + } + ) + + http.get(signedRequest.url, { headers: signedRequest.headers }) +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SystemsManagerClient.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SystemsManagerClient.md new file mode 100644 index 0000000000..29eeeca0ab --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/00 SystemsManagerClient.md @@ -0,0 +1,77 @@ +--- +title: 'SystemsManagerClient' +head_title: 'SystemsManagerClient' +description: 'SystemsManagerClient allows interacting with the AWS Systems Manager Service' +excerpt: 'SystemsManagerClient allows interacting with the AWS Systems Manager Service' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/systemsmanagerclient/ +--- + +`SystemsManagerClient` interacts with the AWS Systems Manager Service. + +With it, the user can get parameters from the Systems Manager Service in the caller's AWS account and region. + +Both the dedicated `ssm.js` jslib bundle and the all-encompassing `aws.js` bundle include the `SystemsManagerClient`. + +### Methods + +| Function | Description | +| :------------------------------------------------------------------------------------------------ | :------------------------------------------------- | +| [getParameter](/javascript-api/jslib/aws/systemsmanagerclient/systemsmanagerclient-getparameter/) | Retrieves a parameter from Amazon Systems Manager. | + +### Throws + +`SystemsManagerClient` methods throw errors in case of failure. + +| Error | Condition | +| :--------------------------- | :-------------------------------------------------------- | +| `InvalidSignatureError` | when using invalid credentials | +| `SystemsManagerServiceError` | when AWS replied to the requested operation with an error | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SystemsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/ssm.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const systemsManager = new SystemsManagerClient(awsConfig); +const testParameterName = 'jslib-test-parameter'; +const testParameterValue = 'jslib-test-value'; +const testParameterSecretName = 'jslib-test-parameter-secret'; +// this value was created with --type SecureString +const testParameterSecretValue = 'jslib-test-secret-value'; + +export default async function () { + // Currently the parameter needs to be created before hand + + // Let's get its value + // getParameter returns a parameter object: e.g. {name: string, value: string...} + const parameter = await systemsManager.getParameter(testParameterName); + if (parameter.value !== testParameterValue) { + exec.test.abort('test parameter not found'); + } + + // Let's get the secret value with decryption + // destructure the parameter object to get to the values you want + const { value: encryptedParameterValue } = await systemsManager.getParameter( + testParameterSecretName, + true + ); + if (encryptedParameterValue !== testParameterSecretValue) { + exec.test.abort('encrypted test parameter not found'); + } +} +``` + +_A k6 script querying a user's Systems Manager Service parameter_ + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/EventBridgeClient/putEvents.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/EventBridgeClient/putEvents.md new file mode 100644 index 0000000000..2398bf606e --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/EventBridgeClient/putEvents.md @@ -0,0 +1,71 @@ +--- +title: 'EventBridgeClient.putEvents' +description: 'EventBridgeClient.putEvents sends custom events to Amazon EventBridge' +excerpt: 'EventBridgeClient.putEvents sends custom events to Amazon EventBridge' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/eventbridgeclient/putevents/ +--- + +`EventBridgeClient.putEvents` sends custom events to Amazon EventBridge so that they can be matched to rules. + +### Parameters + +| Parameter | Type | Description | +| :------------ | :-------------- | :----------------------------------------------------------------------------------------------------------------------- | +| input | [PutEventsInput](#puteventsinput) | An array of objects representing events to be submitted. | + +#### PutEventsInput + +| Parameter | Type | Description | +| :-------- | :-------------- | :----------------------------------------------------------------------------------------------------------------------- | +| Entries | [EventBridgeEntry](#eventbridgeentry)[] | An array of objects representing events to be submitted. | +| EndpointId | string (optional) | The ID of the target to receive the event. | + +#### EventBridgeEntry + +| Parameter | Type | Description | +| :-------- | :----- | :----------------------------------------------------------------------------------------------------------------------- | +| Source | string | The source of the event. | +| Detail | object | A JSON object containing event data. | +| DetailType | string | Free-form string used to decide what fields to expect in the event detail. | +| Resources | string[] (optional) | AWS resources, identified by Amazon Resource Name (ARN), which the event primarily concerns. | +| EventBusName | string (optional) | The event bus that will receive the event. If you omit this, the default event bus is used. Only the AWS account that owns a bus can write to it. | + + +### Returns + +| Type | Description | +| :-------------- | :---------------------------------------------------------------------------------- | +| `Promise` | A Promise that fulfills when the events have been sent to Amazon EventBridge. | + +### Example + + + +```javascript +import { AWSConfig, EventBridgeClient } from 'https://jslib.k6.io/aws/0.11.0/event-bridge.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const eventBridge = new EventBridgeClient(awsConfig); +const eventEntry = { + Source: "my.source", + Detail: { + key: "value" + }, + DetailType: "MyDetailType", + Resources: ["resource-arn"], +}; + +export default async function () { + await eventBridge.putEvents({ + Entries: [eventEntry] + }); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/00 generateDataKey.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/00 generateDataKey.md new file mode 100644 index 0000000000..1b1d9a676b --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/00 generateDataKey.md @@ -0,0 +1,60 @@ +--- +title: 'KMSClient.generateDataKey' +description: 'KMSClient.generateDataKey generates a symmetric data key for use outside of the AWS Key Management Service' +excerpt: 'KMSClient.generateDataKey generates a symmetric data key for use outside of the AWS Key Management Service' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/kmsclient/generatedatakey/ +--- + +`KMSClient.generateDataKey` generates a symmetric data key for use outside of the AWS Key Management Service. + +### Parameters + +| Name | Type | Description | +| :--- | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | string | The identifier of the key. This can be either the key ID or the Amazon Resource Name (ARN) of the key. | +| `size` | number | The length of the data key. For example, use the value 64 to generate a 512-bit data key (64 bytes is 512 bits). For 256-bit (32-byte) data keys, use the value 32, instead. | + +### Returns + +| Type | Description | +| :-------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------- | +| Promise<[KMSDataKey](/javascript-api/jslib/aws/kmsclient/kmsdatakey)> | A Promise that fulfills with a [KMSDataKey](/javascript-api/jslib/aws/kmsclient/kmskey) object. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, KMSClient } from 'https://jslib.k6.io/aws/0.11.0/kms.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const kms = new KMSClient(awsConfig); +const testKeyId = 'e67f95-4c047567-4-a0b7-62f7ce8ec8f48'; + +export default async function () { + // List the KMS keys the AWS authentication configuration + // gives us access to. + const keys = await kms.listKeys(); + + // If our test key does not exist, abort the execution. + if (keys.filter((b) => b.keyId === testKeyId).length == 0) { + exec.test.abort(); + } + + // Generate a data key from the KMS key. + const key = await kms.generateDataKey(testKeyId, 32); +} +``` + +_A k6 script that generating a data key from an AWS Key Management Service key_ + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/00 listKeys.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/00 listKeys.md new file mode 100644 index 0000000000..f1e90cfa8c --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/00 listKeys.md @@ -0,0 +1,50 @@ +--- +title: 'KMSClient.listKeys()' +description: "KMSClient.listKeys lists all the KMS keys in the caller's AWS account and region" +excerpt: "KMSClient.listKeys lists all the KMS keys in the caller's AWS account and region" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/kmsclient/listkeys/ +--- + +`KMSClient.listKeys()` lists all the Key Management Service keys in the caller's AWS account and region. + +### Returns + +| Type | Description | +| :-------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- | +| Promise<[KMSKey[]](/javascript-api/jslib/aws/kmsclient/kmskey)> | A Promise that fulfills with an array of [`KMSKey`](/javascript-api/jslib/aws/kmsclient/kmskey) objects. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, KMSClient } from 'https://jslib.k6.io/aws/0.11.0/kms.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const kms = new KMSClient(awsConfig); +const testKeyId = 'e67f95-4c047567-4-a0b7-62f7ce8ec8f48'; + +export default async function () { + // List the KMS keys the AWS authentication configuration + // gives us access to. + const keys = await kms.listKeys(); + + // If our test key does not exist, abort the execution. + if (keys.filter((b) => b.keyId === testKeyId).length == 0) { + exec.test.abort(); + } +} +``` + +_A k6 script querying the user's Key Management Service keys and verifying their test key exists_ + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/90 KMSDataKey.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/90 KMSDataKey.md new file mode 100644 index 0000000000..f244a7a868 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/90 KMSDataKey.md @@ -0,0 +1,54 @@ +--- +title: 'KMSDataKey' +description: 'KMSDataKey is returned by the KMSClient.*DataKey methods that query KMS data keys' +excerpt: 'KMSDataKey is returned by the KMSClient.*DataKey methods that query KMS data keys' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/kmsclient/kmsdatakey/ +--- + +`KMSClient.*DataKey` methods, querying Key Management Service data keys, return some KMSDataKey instances. +The KMSDataKey object describes an Amazon Key Management Service data key. +For instance, the [`generateDataKey`](/javascript-api/jslib/aws/kmsclient/kmsclient-generatedatakey/) returns the generated KMSDataKey object. + +| Name | Type | Description | +| :-------------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------ | +| `KMSDataKey.id` | string | The identifier of the Key Management Service key that encrypted the data key. | +| `KMSDataKey.ciphertextBlob` | string | The base64-encoded encrypted copy of the data key. | +| `KMSDataKey.plaintext` | string | The plain text data key. Use this data key to encrypt your data outside of Key Management Service. Then, remove it from memory as soon as possible. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, KMSClient } from 'https://jslib.k6.io/aws/0.11.0/kms.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const kms = new KMSClient(awsConfig); +const testKeyId = 'e67f95-4c047567-4-a0b7-62f7ce8ec8f48'; + +export default async function () { + // List the KMS keys the AWS authentication configuration + // gives us access to. + const keys = await kms.listKeys(); + + // If our test key does not exist, abort the execution. + if (keys.filter((b) => b.keyId === testKeyId).length == 0) { + exec.test.abort(); + } + + // Generate a data key from the KMS key. + const key = await kms.generateDataKey(testKeyId, 32); +} +``` + +_A k6 script that generating a data key from an AWS Key Management Service key_ + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/90 KMSKey.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/90 KMSKey.md new file mode 100644 index 0000000000..23a634c6df --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/KMSClient/90 KMSKey.md @@ -0,0 +1,47 @@ +--- +title: 'KMSKey' +description: 'KMSKey is returned by the KMSClient.* methods that query KMS keys' +excerpt: 'KMSKey is returned by the KMSClient.* methods that query KMS keys' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/kmsclient/kmskey/ +--- + +`KMSClient.*` methods querying Key Management Service keys return some `KMSKey` instances. Namely, `listKeys()` returns an array of `KMSKey` objects. The `KMSKey` object describes an Amazon Key Management Service key. + +| Name | Type | Description | +| :-------------- | :----- | :--------------------------- | +| `KMSKey.keyId` | string | Unique identifier of the key | +| `KMSKey.keyArn` | string | ARN of the key | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, KMSClient } from 'https://jslib.k6.io/aws/0.11.0/kms.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const kms = new KMSClient(awsConfig); +const testKeyId = 'e67f95-4c047567-4-a0b7-62f7ce8ec8f48'; + +export default async function () { + // List the KMS keys the AWS authentication configuration + // gives us access to. + const keys = await kms.listKeys(); + + // If our test key does not exist, abort the execution. + if (keys.filter((b) => b.keyId === testKeyId).length == 0) { + exec.test.abort(); + } +} +``` + +_A k6 script querying the user's Key Management Service keys and verifying their test key exists_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 abortMultipartUpload(bucketName, objectKey, uploadId).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 abortMultipartUpload(bucketName, objectKey, uploadId).md new file mode 100755 index 0000000000..4db0f94955 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 abortMultipartUpload(bucketName, objectKey, uploadId).md @@ -0,0 +1,54 @@ +--- +title: 'S3Client.abortMultipartUpload(bucketName, objectKey, uploadId)' +description: 'S3Client.abortMultipartUpload aborts a multipart upload to a bucket' +excerpt: 'S3Client.abortMultipartUpload aborts a multipart upload to a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/abortmultipartupload/ +--- + +`S3Client.abortMultipartUpload` aborts a multipart upload to an S3 bucket. + +### Parameters + +| Parameter | Type | Description | +| :--------- | :-------------------- | :----------------------------------------------------- | +| bucketName | string | Name of the bucket to delete the multipart object from.| +| objectKey | string | Name of the multipart object to delete. | +| uploadId | number | UploadId of the multipart upload to abort. | + +### Returns + +| Type | Description | +| :-------------- | :------------------------------------------------------------------ | +| `Promise` | A promise that fulfills when the multipart upload has been aborted. | + +### Example + + + +```javascript +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + + // Abort multipart upload + await s3.abortMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId); +} +``` + +_A k6 script that will create a multipart upload and abort the multipart_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 completeMultipartUpload(bucketName, objectKey, uploadId, parts).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 completeMultipartUpload(bucketName, objectKey, uploadId, parts).md new file mode 100755 index 0000000000..fde3652aeb --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 completeMultipartUpload(bucketName, objectKey, uploadId, parts).md @@ -0,0 +1,99 @@ +--- +title: 'S3Client.completeMultipartUpload(bucketName, objectKey, uploadId, parts)' +description: 'S3Client.completeMultipartUpload uploads a multipar object to a bucket' +excerpt: 'S3Client.completeMultipartUpload uploads a multipart object to a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/completemultipartupload/ +--- + +`S3Client.completeMultipartUpload` uploads a multipart object to an S3 bucket. + +### Parameters + +| Parameter | Type | Description | +| :--------- | :------------------------------------------------------------- | :--------------------------------------------------------------------- | +| bucketName | string | Name of the bucket to delete the object to. | +| objectKey | string | Name of the uploaded object. | +| uploadId | number | UploadId of the multipart upload to complete. | +| parts | Array<[S3Part](/javascript-api/jslib/aws/s3client/s3part)> | The [S3Part](/javascript-api/jslib/aws/s3client/s3part)s to assemble. | + +### Returns + +| Type | Description | +| :-------------- | :-------------------------------------------------------------------- | +| `Promise` | A Promise that fulfills when the multipart upload has been completed. | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // List the buckets the AWS authentication configuration + // gives us access to. + const buckets = await s3.listBuckets(); + + // If our test bucket does not exist, abort the execution. + if (buckets.filter((b) => b.name === testBucketName).length == 0) { + exec.test.abort(); + } + + // Produce random bytes to upload of size ~12MB, that + // we will upload in two 6MB parts. This is done as the + // minimum part size supported by S3 is 5MB. + const bigFile = crypto.randomBytes(12 * 1024 * 1024); + + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + + // Upload the first part + const firstPartData = bigFile.slice(0, 6 * 1024 * 1024); + const firstPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 1, + firstPartData + ); + + // Upload the second part + const secondPartData = bigFile.slice(6 * 1024 * 1024, 12 * 1024 * 1024); + const secondPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 2, + secondPartData + ); + + // Complete the multipart upload + await s3.completeMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId, [ + firstPart, + secondPart, + ]); + + // Let's redownload it verify it's correct, and delete it + const obj = await s3.getObject(testBucketName, testFileKey); + await s3.deleteObject(testBucketName, testFileKey); +} +``` + +_A k6 script that will upload a multipart upload to an S3 bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 copyObject.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 copyObject.md new file mode 100644 index 0000000000..21eafc547f --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 copyObject.md @@ -0,0 +1,58 @@ +--- +title: 'S3Client.copyObject' +description: 'S3Client.copyObject copies an object from a bucket to another' +excerpt: 'S3Client.copyObject copies an object from a bucket to another' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/copyobject/ +--- + +`S3Client.copyObject` copies an object from one bucket to another. + +### Parameters + +| Parameter | Type | Description | +| :---------------- | :----- | :------------------------------------------------- | +| sourceBucket | string | Name of the bucket to copy the object from. | +| sourceKey | string | Name of the object to copy from the source bucket. | +| destinationBucket | string | Name of the bucket to copy the object to. | +| destinationKey | string | Name of the destination object. | + +### Returns + +| Type | Description | +| :-------------- | :---------------------------------------------------------------------------------- | +| `Promise` | A Promise that fulfills when the object has been copied from one bucket to another. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const testFile = open('./bonjour.txt', 'r'); +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'bonjour.txt'; +const testDestinationBucketName = 'test-jslib-aws-destination'; + +export default async function () { + // Let's upload our test file to the bucket + await s3.putObject(testBucketName, testFileKey, testFile); + + // Let's create our destination bucket + await s3.copyObject(testBucketName, testFileKey, testDestinationBucketName, testFileKey); +} +``` + +_A k6 script that will copy an object from a source S3 bucket to a destination bucket_ + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 createMultipartUpload(bucketName, objectKey).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 createMultipartUpload(bucketName, objectKey).md new file mode 100755 index 0000000000..bcedb71c2e --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 createMultipartUpload(bucketName, objectKey).md @@ -0,0 +1,51 @@ +--- +title: 'S3Client.createMultipartUpload(bucketName, objectKey)' +description: 'S3Client.createMultipartUpload creates a multipart upload for an object key to a bucket' +excerpt: 'S3Client.createMultipartUpload creates a multipart upload to a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/createmultipartupload/ +--- + +`S3Client.createMultipartUpload` creates a new multipart upload for a given an object key in a bucket. + +| Parameter | Type | Description | +| :--------- | :-------------------- | :------------------------------------------- | +| bucketName | string | Name of the bucket to upload the object to. | +| objectKey | string | Name of the uploaded object. | + +### Returns + +| Type | Description | +| :----------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| Promise<[S3MultipartUpload](/javascript-api/jslib/aws/s3client/s3multipartupload)> | A Promise that fulfills with a [S3MultipartUpload](/javascript-api/jslib/aws/s3client/s3multipartupload) representing a S3 Multipart Upload. | + +### Example + + + +```javascript +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + + // Abort multipart upload + await s3.abortMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId); +} +``` + +_A k6 script that will create a multipart upload to an S3 bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 deleteObject(bucketName, objectKey).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 deleteObject(bucketName, objectKey).md new file mode 100755 index 0000000000..a21dd58353 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 deleteObject(bucketName, objectKey).md @@ -0,0 +1,56 @@ +--- +title: 'S3Client.deleteObject(bucketName, objectKey)' +description: 'S3Client.deleteObject deletes an object from a bucket' +excerpt: 'S3Client.deleteObject deletes an object from a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/deleteobject/ +--- + +`S3Client.deleteObject` deletes an object from a bucket. + +### Parameters + +| Parameter | Type | Description | +| :--------- | :-------------------- | :------------------------------------------- | +| bucketName | string | Name of the bucket to delete the object from.| +| objectKey | string | Name of the object to delete. | + +### Returns + +| Type | Description | +| :-------------- | :------------------------------------------------------------------ | +| `Promise` | A promise that fulfills when the object has been deleted from S3. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'bonjour.txt'; + +export default async function () { + // Let's delete our test object + await s3.deleteObject(testBucketName, testFileKey); + + // And make sure it was indeed deleted + const objects = await s3.listObjects(); + if (objects.filter((o) => o.name === testBucketName).length != 0) { + exec.test.abort(); + } +} +``` + +_A k6 script that will delete an object from a S3 bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 getObject(bucketName, objectKey).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 getObject(bucketName, objectKey).md new file mode 100755 index 0000000000..709cbac9d6 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 getObject(bucketName, objectKey).md @@ -0,0 +1,58 @@ +--- +title: 'S3Client.getObject(bucketName, objectKey)' +description: 'S3Client.getObject downloads an object from a bucket' +excerpt: 'S3Client.getObject downloads an object from a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/getobject/ +--- + +`S3Client.getObject` downloads an object from a bucket. + +### Parameters + +| Parameter | Type | Description | +| :--------- | :----- | :------------------------------------------- | +| bucketName | string | Name of the bucket to fetch the object from. | +| objectKey | string | Name of the object to download. | + +### Returns + +| Type | Description | +| :----------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | +| Promise<[Object](/javascript-api/jslib/aws/s3client/object)> | A Promise that fulfills with an [Object](/javascript-api/jslib/aws/s3client/object) describing and holding the downloaded content. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'bonjour.txt'; + +export default async function () { + const objects = await s3.listObjects(testBucketName); + + // If our test object does not exist, abort the execution. + if (objects.filter((o) => o.key === testFileKey).length == 0) { + exec.test.abort(); + } + + // Let's download our test object and print its content + const object = await s3.getObject(testBucketName, testFileKey); + console.log(JSON.stringify(object)); +} +``` + +_A k6 script that will download an object from a bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 listBuckets().md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 listBuckets().md new file mode 100644 index 0000000000..525dc9bb89 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 listBuckets().md @@ -0,0 +1,50 @@ +--- +title: 'S3Client.listBuckets()' +description: 'S3Client.listBuckets lists the buckets the authenticated user has access to' +excerpt: 'S3Client.listBuckets lists the buckets the authenticated user has access to' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/listbuckets/ +--- + +`S3Client.listBuckets()` lists the buckets the authenticated user has access to in the region set by the `S3Client` instance's configuration. + +### Returns + +| Type | Description | +| :------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------- | +| Promise> | A Promise that fulfills with an array of [Bucket](/javascript-api/jslib/aws/s3client/bucket) objects. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; + +export default async function () { + // List the buckets the AWS authentication configuration + // gives us access to. + const buckets = await s3.listBuckets(); + + // If our test bucket does not exist, abort the execution. + if (buckets.filter((b) => b.name === testBucketName).length == 0) { + exec.test.abort(); + } + + // ... work with the bucket's content +} +``` + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 listObjects(bucketName, [prefix]).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 listObjects(bucketName, [prefix]).md new file mode 100755 index 0000000000..b4993d335d --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 listObjects(bucketName, [prefix]).md @@ -0,0 +1,56 @@ +--- +title: 'S3Client.listObjects(bucketName, [prefix])' +description: 'S3Client.listObjects lists the objects contained in a bucket' +excerpt: 'S3Client.listObjects lists the objects contained in a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/listobjects/ +--- + +`S3Client.listObjects()` lists the objects contained in a bucket. + +### Parameters + +| Parameter | Type | Description | +| :---------------- | :----- | :---------------------------------------------------------------- | +| bucketName | string | Name of the bucket to fetch the object from. | +| prefix (optional) | string | Limits the response to keys that begin with the specified prefix. | + +### Returns + +| Type | Description | +| :------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------- | +| Promise> | A Promise that fulfills with an array of [Object](/javascript-api/jslib/aws/s3client/object) objects. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'bonjour.txt'; + +export default async function () { + // List our bucket's objects + const objects = await s3.listObjects(testBucketName); + + // If our test object does not exist, abort the execution. + if (objects.filter((o) => o.key === testFileKey).length == 0) { + exec.test.abort(); + } + + // ... work with the bucket's objects + console.log(JSON.stringify(objects)); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 putObject(bucketName, objectKey, data).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 putObject(bucketName, objectKey, data).md new file mode 100755 index 0000000000..e8e0044628 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 putObject(bucketName, objectKey, data).md @@ -0,0 +1,68 @@ +--- +title: 'S3Client.putObject(bucketName, objectKey, data)' +description: 'S3Client.putObject uploads an object to a bucket' +excerpt: 'S3Client.putObject uploads an object to a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/putobject/ +--- + +`S3Client.putObject` uploads an object to a bucket. + +### Parameters + +| Parameter | Type | Description | +| :------------ | :---------------------------------------------- | :------------------------------------------- | +| `bucketName` | string | Name of the bucket to upload the object to. | +| `objectKey` | string | Name of the uploaded object. | +| `data` | string \| ArrayBuffer | Content of the object to upload. | +| `params` | [PutObjectParams](#putobjectparams) (optional) | Options for the request. | + +#### PutObjectParams + +| Name | Type | Description | +| :-------------------- | :---------------- | :---------- | +| `contentDisposition` | string (optional) | Specifies presentational information for the object. For more information, see [RFC 6266](https://tools.ietf.org/html/rfc6266). | +| `contentEncoding` | string (optional) | Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. For more information, see [RFC 2616](https://tools.ietf.org/html/rfc2616). | +| `contentLength` | number (optional) | Size of the body in bytes. This parameter is useful when the size of the body cannot be determined automatically. | +| `contentMD5` | string (optional) | The base64-encoded 128-bit MD5 digest of the message (without the headers) according to RFC 1864. This header can be used as a message integrity check to verify that the received message is identical to the message that was sent. | +| `contentType` | string (optional) | A standard MIME type describing the format of the object data. For more information, see [RFC 2616](https://tools.ietf.org/html/rfc2616). | + +### Returns + +| Type | Description | +| :-------------- | :-------------------------------------------------------------------------- | +| `Promise` | A Promise that fulfills when the object has been uploaded to the S3 bucket. | + +### Example + + + +```javascript +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'bonjour.txt'; +const testFile = open('./bonjour.txt', 'r'); + +export default async function () { + // Let's upload our test file to the bucket + await s3.putObject(testBucketName, testFileKey, testFile, { + contentType: 'text/plain', + contentLength: testFile.length, + }); + + // And let's redownload it to verify it's correct + const obj = await s3.getObject(testBucketName, testFileKey); + console.log(JSON.stringify(obj)); +} +``` + +_A k6 script that will upload an object to a S3 bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 uploadPart(bucketName, objectKey, uploadId, partNumber, data) copy.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 uploadPart(bucketName, objectKey, uploadId, partNumber, data) copy.md new file mode 100755 index 0000000000..255a74d3d3 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/00 uploadPart(bucketName, objectKey, uploadId, partNumber, data) copy.md @@ -0,0 +1,89 @@ +--- +title: 'S3Client.uploadPart(bucketName, objectKey, uploadId,partNumber, data)' +description: 'S3Client.uploadPart a part in a multipart upload to a bucket' +excerpt: 'S3Client.uploadPart a part in a multipart upload to a bucket' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/uploadpart/ +--- + +`S3Client.uploadPart` uploads a part to multipart upload in a bucket. + +| Parameter | Type | Description | +| :--------- | :-------------------- | :------------------------------------------- | +| bucketName | string | Name of the bucket to upload the object to. | +| objectKey | string | Name of the object to upload. | +| uploadId | string | UploadId of the multipart upload. | +| partNumber | number | The Part number of the Part to upload. | +| data | string \| ArrayBuffer | Content of the part to upload. | + +### Returns + +| Type | Description | +| :----------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| Promise<[S3Part](/javascript-api/jslib/aws/s3client/s3part)> | A Promise that fulfills with a [S3Part](/javascript-api/jslib/aws/s3client/s3part) representing a S3 Part Upload. | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // Produce random bytes to upload of size ~12MB, that + // we will upload in two 6MB parts. This is done as the + // minimum part size supported by S3 is 5MB. + const bigFile = crypto.randomBytes(12 * 1024 * 1024); + + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + + // Upload the first part + const firstPartData = bigFile.slice(0, 6 * 1024 * 1024); + const firstPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 1, + firstPartData + ); + + // Upload the second part + const secondPartData = bigFile.slice(6 * 1024 * 1024, 12 * 1024 * 1024); + const secondPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 2, + secondPartData + ); + + // Complete the multipart upload + await s3.completeMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId, [ + firstPart, + secondPart, + ]); + + // Let's redownload it verify it's correct, and delete it + const obj = await s3.getObject(testBucketName, testFileKey); + await s3.deleteObject(testBucketName, testFileKey); +} +``` + +_A k6 script that will upload a part in a multipart upload to an S3 bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 Bucket.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 Bucket.md new file mode 100755 index 0000000000..b9741f96ee --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 Bucket.md @@ -0,0 +1,40 @@ +--- +title: 'Bucket' +description: 'Bucket is returned by the S3Client.* methods who query S3 buckets.' +excerpt: 'Bucket is returned by the S3Client.* methods who query S3 buckets.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/bucket/ +--- + +Bucket is returned by the S3Client.* methods that query S3 buckets. Namely, `listBuckets()` returns an array of Bucket objects. The Bucket object describes an Amazon S3 bucket. + +| Name | Type | Description | +| :-------------------- | :----- | :--------------------------- | +| `Bucket.name` | string | The S3 bucket's name | +| `Bucket.creationDate` | Date | The S3 bucket's creationDate | + +### Example + + + +```javascript +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); + +export default async function () { + // List the buckets the AWS authentication configuration + // gives us access to. + const buckets = await s3.listBuckets(); + console.log(JSON.stringify(buckets)); +} +``` + +_A k6 script that will query the user's S3 buckets and print all of their metadata_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 Object.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 Object.md new file mode 100755 index 0000000000..f13d0ca3dd --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 Object.md @@ -0,0 +1,60 @@ +--- +title: 'Object' +description: "Object is returned by the S3Client.* methods who query S3 buckets' objects." +excerpt: "Object is returned by the S3Client.* methods who query S3 buckets' objects." +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/object/ +--- + +Object is returned by the S3Client.\* methods that query S3 buckets' objects. Namely, [`listObjects`](/javascript-api/jslib/aws/s3client/s3client-listobjects), [`getObject`](/javascript-api/jslib/aws/s3client/s3client-getobject), [`putObject`](/javascript-api/jslib/aws/s3client/s3client-putobject), +and [`deleteObject`](/javascript-api/jslib/aws/s3client/s3client-deleteobject). The Object construct describes an Amazon S3 object. + +| Name | Type | Description | +| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Object.key` | string | The S3 object's name. | +| `Object.lastModified` | number | The S3 object's last modification date. | +| `Object.etag` | string | The S3 object's `etag` is a hash of the object. The ETag reflects changes only to the contents of an object, not its metadata. The ETag may or may not be an MD5 digest of the object data. | +| `Object.size` | size | The S3 object's size in bytes. | +| `Object.storageClass` | `STANDARD` \| `REDUCED_REDUNDANCY` \| `GLACIER` \| `STANDARD_IA` \| `INTELLIGENT_TIERING` \| `DEEP_ARCHIVE` \| `OUTPOSTS` \| `GLACIER_IR` | The S3 object's class of storage used to store it. | +| `Object.data` | `string` or `bytes` or `null` | The S3 object's content. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { + // listBuckets, + AWSConfig, + S3Client, +} from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const s3 = new S3Client(awsConfig); +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'bonjour.txt'; + +export default async function () { + const objects = await s3.listObjects(testBucketName); + + // If our test object does not exist, abort the execution. + if (objects.filter((o) => o.key === testFileKey).length == 0) { + exec.test.abort(); + } + + // Let's download our test object and print its content + const object = await s3.getObject(testBucketName, testFileKey); + console.log(JSON.stringify(object)); +} +``` + +_A k6 script that will query a S3 bucket's objects and print its content and metadata_ + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 S3MultipartUpload.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 S3MultipartUpload.md new file mode 100755 index 0000000000..8404878163 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 S3MultipartUpload.md @@ -0,0 +1,46 @@ +--- +title: 'S3MultipartUpload' +description: 'S3MultipartUpload is returned by the S3Client.createMultipartUpload method when creating a multipart upload.' +excerpt: 'S3MultipartUpload is returned by the S3Client.createMultipartUpload method when creating a multipart upload.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/s3multipartupload/ +--- + +S3MultipartUpload is returned by the [`createMultipartUpload(bucketName, objectKey)`](/javascript-api/jslib/aws/s3client/s3client-createmultipartupload/) method when creating a [multipart upload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html). + +| Name | Type | Description | +| :------------------------------ | :----- | :----------------------------- | +| `S3MultipartUpload.key` | string | The S3 Multipart object's key | +| `S3MultipartUpload.uploadId` | Date | The S3 Multipart upload Id | + +### Example + + + +```javascript +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + console.log(multipartUpload.uploadId); + + // Abort multipart upload + await s3.abortMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId); +} +``` + +_A k6 script that will create a multipart upload and log the multipart `uploadId` and abort the multipart upload_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 S3Part.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 S3Part.md new file mode 100755 index 0000000000..8f9555f3b8 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/S3Client/90 S3Part.md @@ -0,0 +1,80 @@ +--- +title: 'S3Part' +description: 'S3Part is returned by the S3Client.uploadPart method when uploading a part to a multipart upload.' +excerpt: 'S3Part is returned by the S3Client.uploadPart method when uploading a part to a multipart upload.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/s3client/s3part/ +--- + +S3Part is returned by the [`uploadPart(bucketName, objectKey, uploadId, partNumber, data)`](/javascript-api/jslib/aws/s3client/s3client-uploadpart/) method when uploading a part to a multipart upload. The S3Part object describes an Amazon S3 Part. + +| Name | Type | Description | +| :-------------------- | :----- | :---------------------- | +| `S3Part.partNumber` | number | The S3 Part'number | +| `S3Part.eTag ` | String | The S3 Part's etag | + +### Example + + + +```javascript +import crypto from 'k6/crypto'; +import exec from 'k6/execution'; + +import { AWSConfig, S3Client } from 'https://jslib.k6.io/aws/0.11.0/s3.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const s3 = new S3Client(awsConfig); + +const testBucketName = 'test-jslib-aws'; +const testFileKey = 'multipart.txt'; + +export default async function () { + // Produce random bytes to upload of size ~12MB, that + // we will upload in two 6MB parts. This is done as the + // minimum part size supported by S3 is 5MB. + const bigFile = crypto.randomBytes(12 * 1024 * 1024); + + // Initialize a multipart upload + const multipartUpload = await s3.createMultipartUpload(testBucketName, testFileKey); + + // Upload the first part + const firstPartData = bigFile.slice(0, 6 * 1024 * 1024); + const firstPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 1, + firstPartData + ); + + // Upload the second part + const secondPartData = bigFile.slice(6 * 1024 * 1024, 12 * 1024 * 1024); + const secondPart = await s3.uploadPart( + testBucketName, + testFileKey, + multipartUpload.uploadId, + 2, + secondPartData + ); + + // Complete the multipart upload + await s3.completeMultipartUpload(testBucketName, testFileKey, multipartUpload.uploadId, [ + firstPart, + secondPart, + ]); + + // Let's redownload it verify it's correct, and delete it + const obj = await s3.getObject(testBucketName, testFileKey); + await s3.deleteObject(testBucketName, testFileKey); +} +``` + +_A k6 script that will upload a part in a multipart upload to an S3 bucket_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SQSClient/00 listQueues.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SQSClient/00 listQueues.md new file mode 100644 index 0000000000..3a8c146651 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SQSClient/00 listQueues.md @@ -0,0 +1,55 @@ +--- +title: 'SQSClient.listQueues()' +description: "SQSClient.listQueues retrieves a list of available Amazon SQS queues" +excerpt: "SQSClient.listQueues retrieves a list of available Amazon SQS queues" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/sqsclient/sqsclient-listqueues/ +--- + +`SQSClient.listQueues(options)` retrieves a list of available Amazon Simple Queue Service (SQS) queues. + +### Parameters + +| Name | Type | Description | +| :------------ | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `options` | object (optional) | Options for the request. Accepted properties are: `queueNamePrefix` (optional string) setting the prefix filter for the returned queue list, `maxResults` (optional number) setting the maximum number of results to include in the response (1 <= `maxResults` <= 1000>), and `nextToken` (optional string) setting the pagination token to request the next set of results. | + +### Returns + +| Type | Description | +| :---------------------------------------------------------- | :------------------------------------------------------------------------ | +| `Promise` | A Promise that fulfills with an object with an `urls` property containing an array of queue URLs, and an optional `nextToken` containing a pagination token to include in the next request when relevant. | + +### Example + + + +```javascript +import exec from 'k6/execution' + +import { AWSConfig, SQSClient } from 'https://jslib.k6.io/aws/0.11.0/sqs.js' + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}) + +const sqs = new SQSClient(awsConfig) +const testQueue = 'https://sqs.us-east-1.amazonaws.com/000000000/test-queue' + +export default async function () { + // List all queues in the AWS account + const queuesResponse = await sqs.listQueues() + + // If our test queue does not exist, abort the execution. + if (queuesResponse.queueUrls.filter((q) => q === testQueue).length == 0) { + exec.test.abort() + } + + // Send message to test queue + await sqs.sendMessage(testQueue, JSON.stringify({value: '123'})); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SQSClient/00 sendMessage.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SQSClient/00 sendMessage.md new file mode 100644 index 0000000000..a02ce04407 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SQSClient/00 sendMessage.md @@ -0,0 +1,79 @@ +--- +title: 'SQSClient.sendMessage()' +description: "SQSClient.sendMessage sends a message to the specified Amazon SQS queue" +excerpt: "SQSClient.sendMessage sends a message to the specified Amazon SQS queue" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/sqsclient/sqsclient-sendmessage/ +--- + +`SQSClient.sendMessage(queueUrl, messageBody, options)` sends a message to the specified Amazon Simple Queue Service (SQS) queue. + +### Parameters + +| Name | Type | Description | +| :------------ | :---------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `queueUrl` | string | The URL of the Amazon SQS queue to which a message is sent. Queue URLs and names are case-sensitive. | +| `messageBody` | string | The message to send. The minimum size is one character. The maximum size is 256 KB. | +| `options` | [SendMessageOptions](#sendmessageoptions) (optional) | Options for the request. | + +#### SendMessageOptions + +| Name | Type | Description | +| :------------------------ | :----- | :---------------------------------------------------------------------------------------------- | +| `messageDeduplicationId` | string (optional) | The token used for deduplication of sent messages. This parameter applies only to FIFO (first-in-first-out) queues. If a message with a particular MessageDeduplicationId is sent successfully, any messages with the same MessageDeduplicationId are accepted but not delivered during the 5-minute deduplication interval. | +| `messageGroupId` | string (optional) | The tag that specifies that a message belongs to a specific message group. Messages that belong to the same message group are processed in a FIFO manner. Messages in different message groups might be processed out of order. | +| `messageAttributes` | object (optional) | Each message attribute consists of a `Name`, `Type`, and `Value`. For more information, see [Amazon SQS Message Attributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html). | +| `delaySeconds` | number (optional) | The length of time, in seconds, for which to delay a specific message. Valid values: 0 to 900. Maximum: 15 minutes. Messages with a positive `delaySeconds` value become available for processing after the delay period is finished. If you don't specify a value, the default value for the queue applies. | + +### Returns + +| Type | Description | +| :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Promise` | A Promise that fulfills with the message that was sent, as an object containing an `id` string property holding the unique identifier for the message, and a `bodyMD5` string property holding the MD5 digest of the non-URL-encoded message body string. | + +### Example + + + +```javascript +import exec from 'k6/execution' + +import { AWSConfig, SQSClient } from 'https://jslib.k6.io/aws/0.11.0/sqs.js' + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}) + +const sqs = new SQSClient(awsConfig) +const testQueue = 'https://sqs.us-east-1.amazonaws.com/000000000/test-queue' + +export default async function () { + // If our test queue does not exist, abort the execution. + const queuesResponse = await sqs.listQueues() + if (queuesResponse.queueUrls.filter((q) => q === testQueue).length == 0) { + exec.test.abort() + } + + // Send message to test queue + await sqs.sendMessage(testQueue, 'test', { + messageAttributes: { + 'test-string': { + type: 'String', + value: 'test' + }, + 'test-number': { + type: 'Number', + value: '23' + }, + 'test-binary': { + type: 'Binary', + value: 'dGVzdA==' + } + } + }); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 createSecret(name, secretString, description, [versionID], [tags]).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 createSecret(name, secretString, description, [versionID], [tags]).md new file mode 100644 index 0000000000..7f1ae48fa5 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 createSecret(name, secretString, description, [versionID], [tags]).md @@ -0,0 +1,59 @@ +--- +title: 'SecretsManagerClient.createSecret(name, secretString, description, [versionID], [tags])' +description: 'SecretsManagerClient.createSecret creates a new secret' +excerpt: 'SecretsManagerClient.createSecret creates a new secret' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/createsecret/ +--- + +`SecretsManagerClient.createSecret` creates a secret in AWS' secrets manager. + +### Parameters + +| Parameter | Type | Description | +| :------------------- | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | +| name | string | The friendly name of the secret. You can use forward slashes in the name to represent a path hierarchy. | +| secretString | string | The text data to encrypt and store in this new version of the secret. We recommend you use a JSON structure of key/value pairs for your secret value. | +| description | string | The description of the secret. | +| versionID (optional) | string | Optional unique version identifier for the created secret. If no versionID is provided, an auto-generated UUID will be used instead. | +| tags (optional) | Array<{"key": "value"},> | A list of tags to attach to the secret. Each tag is a key and value pair of strings in a JSON text string | + +### Returns + +| Type | Description | +| :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | +| Promise<[Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret)> | A Promise that fulfills with a [Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret) object that contains the details of the created secret. | + +### Example + + + +```javascript +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; +const testSecretValue = 'jslib-test-value'; + +export default async function () { + // Let's create our test secret. + const testSecret = await secretsManager.createSecret( + testSecretName, + testSecretValue, + 'this is a test secret, delete me.' + ); + + // Let's get its value and verify it was indeed created. + const createdSecret = await secretsManager.getSecret(testSecretName); + console.log(JSON.stringify(createdSecret)); +} +``` + +_A k6 script that will create a secret in AWS secrets manager_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 deleteSecret.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 deleteSecret.md new file mode 100644 index 0000000000..448dfc8189 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 deleteSecret.md @@ -0,0 +1,56 @@ +--- +title: 'SecretsManagerClient.deleteSecret(secretID, { recoveryWindow: 30, noRecovery: false}})' +description: 'SecretsManagerClient.deleteSecret deletes a secret' +excerpt: 'SecretsManagerClient.deleteSecret deletes a secret' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/deletesecret/ +--- + +`SecretsManagerClient.deleteSecret` deletes a secret from AWS' secrets manager. + +### Parameters + +| Parameter | Type | Description | +| :-------- | :---------------------------------------- | :--------------------------------------- | +| secretID | string | The ARN or name of the secret to update. | +| options | { recoveryWindow: 30, noRecovery: false } | Use options to control the deletion behavior. recoveryWindow defines how long a secret will remain “soft-deleted”, in days, before being hard-deleted. noRecovery set to true would hard-delete the secret immediately. Note that both options are exclusive. | + +### Returns + +| Type | Description | +| :-------------- | :--------------------------------------------------------- | +| `Promise` | A promise that will be resolved when the secret is deleted | + +### Example + + + +```javascript +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; +const testSecretValue = 'jslib-test-value'; + +export default async function () { + // Let's make sure our test secret is created + const testSecret = await secretsManager.createSecret( + testSecretName, + testSecretValue, + 'this is a test secret, delete me.' + ); + + // Let's hard delete our test secret and verify it worked + await secretsManager.deleteSecret(testSecretName, { noRecovery: true }); +} +``` + +_A k6 script that will delete a secret in AWS secrets manager_ + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 getSecret(secretID).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 getSecret(secretID).md new file mode 100644 index 0000000000..9484b802d1 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 getSecret(secretID).md @@ -0,0 +1,55 @@ +--- +title: 'SecretsManagerClient.getSecret(secretID)' +description: 'SecretsManagerClient.getSecret(secretID) downloads a secret from AWS secrets manager' +excerpt: 'SecretsManagerClient.getSecret(secretID) downloads a secret from AWS secrets manager' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/getsecret/ +--- + +`SecretsManagerClient.getSecret` downloads a secret from AWS secrets manager. + +| Parameter | Type | Description | +| :--------- | :----- | :------------------------------------------- | +| secretID | string | The ARN or name of the secret to retrieve. | + +### Returns + +| Type | Description | +| :-------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- | +| Promise<[Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret)> | A Promise that fulfills with a [Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret) describing and holding the downloaded secret. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; + +export default async function () { + // List the secrets the AWS authentication configuration + // gives us access to. + const secrets = await secretsManager.listSecrets(); + if (secrets.filter((s) => s.name === testSecretName).length == 0) { + exec.test.abort('test secret not found'); + } + + // Let's get our test secret's value and print it. + const secret = await secretsManager.getSecret(testSecretName); + console.log(JSON.stringify(secret)); +} +``` + +_A k6 script that will download a user's secret from AWS secrets manager_ + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 listSecrets().md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 listSecrets().md new file mode 100644 index 0000000000..ed8252f370 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 listSecrets().md @@ -0,0 +1,48 @@ +--- +title: 'SecretsManagerClient.listSecrets()' +description: 'SecretsManagerClient.listSecrets lists the secrets the authenticated user has access to' +excerpt: 'SecretsManagerClient.listSecrets lists the secrets the authenticated user has access to' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/listsecrets/ +--- + +`S3Client.listSecrets` lists the secrets the authenticated user has access to in the region set by the `SecretsManagerClient` instance's configuration. + +### Returns + +| Type | Description | +| :--------------------------------------------------------------------- | :----------------------------------------------------------------------------------- | +| Promise> | A Promise that fulfills with an array of [Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret) objects. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; + +export default async function () { + // List the secrets the AWS authentication configuration + // gives us access to, and verify the test secret exists. + const secrets = await secretsManager.listSecrets(); + if (secrets.filter((s) => s.name === testSecretName).length == 0) { + exec.test.abort('test secret not found'); + } + + console.log(JSON.stringify(secrets)); +} +``` + +_A k6 script that will list a user's secrets from AWS secrets manager_ + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 putSecretValue(secretID, secretString, [versionID]).md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 putSecretValue(secretID, secretString, [versionID]).md new file mode 100644 index 0000000000..c48486c844 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/00 putSecretValue(secretID, secretString, [versionID]).md @@ -0,0 +1,64 @@ +--- +title: 'SecretsManagerClient.putSecretValue(secretID, secretString, [versionID], [tags])' +description: "SecretsManagerClient.putSecretValue updates an existing secret's value" +excerpt: "SecretsManagerClient.putSecretValue updates an existing secret's value" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/putsecretvalue/ +--- + +`SecretsManagerClient.putSecretValue` updates a secret's value in AWS' secrets manager. + +| Parameter | Type | Description | +| :------------------- | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | +| secretID | string | The ARN or name of the secret to update. | +| secretString | string | The text data to encrypt and store in this new version of the secret. We recommend you use a JSON structure of key/value pairs for your secret value. | +| versionID (optional) | string | Optional unique version identifier for the updated version of the secret. If no versionID is provided, an auto-generated UUID will be used instead. | +| tags (optional) | Array<{"key": "value"},> | A list of tags to attach to the secret. Each tag is a key and value pair of strings in a JSON text string | + +### Returns + +| Type | Description | +| :--- | ----------- | +| Promise<[Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret)> | A Promise that fulfills with the updated [Secret](/javascript-api/jslib/aws/secretsmanagerclient/secret). | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; +const testSecretValue = 'jslib-test-value'; + +export default async function () { + // Let's make sure our test secret is created + const testSecret = await secretsManager.createSecret( + testSecretName, + testSecretValue, + 'this is a test secret, delete me.' + ); + + // Now that we know the secret exist, let's update its value + const newTestSecretValue = 'new-test-value'; + const u = await secretsManager.putSecretValue(testSecretName, newTestSecretValue); + + // Let's get its value back and verify it was indeed updated + const updatedSecret = await secretsManager.getSecret(testSecretName); + if (updatedSecret.secret !== newTestSecretValue) { + exec.test.abort('unable to update test secret'); + } +} +``` + +_A k6 script that will update a secret's value in AWS secrets manager_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/99 Secret.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/99 Secret.md new file mode 100644 index 0000000000..77cb6e8666 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SecretsManagerClient/99 Secret.md @@ -0,0 +1,59 @@ +--- +title: 'Secret' +description: 'Secret is returned by the SecretsManagerClient.* methods who query secrets from AWS secrets manager.' +excerpt: 'Secret is returned by the SecretsManagerClient.* methods who query secrets from AWS secrets manager.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/secretsmanagerclient/secret/ +--- + +Secret is returned by the SecretsManagerClient.* methods that query secrets. Namely, [listSecrets](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-listsecrets/), +[getSecret](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-getsecret), +[createSecret](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-createsecret), and +[putSecretValue](/javascript-api/jslib/aws/secretsmanagerclient/secretsmanagerclient-putsecretvalue) returns either an instance or array of Secret objects. The Secret object describes an Amazon Secrets Manager secret. + +| Name | Type | Description | +| :----------------------- | :---------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | +| `Secret.name` | string | The friendly name of the secret. You can use forward slashes in the name to represent a path hierarchy. | +| `Secret.arn` | string | The Amazon Resource Name (ARN) of the secret. | +| `Secret.createdAt` | number | The date and time (timestamp) when a secret was created. | +| `Secret.lastAccessDate` | number | The last date that this secret was accessed. This value is truncated to midnight of the date and therefore shows only the date, not the time. | +| `Secret.lastChangedDate` | number | The last date and time that this secret was modified in any way. | +| `Secret.tags` | Array<{"key": "value"}> | The list of user-defined tags associated with the secret. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SecretsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/secrets-manager.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, +}); + +const secretsManager = new SecretsManagerClient(awsConfig); +const testSecretName = 'jslib-test-secret'; + +export default async function () { + // List the secrets the AWS authentication configuration + // gives us access to. + const secrets = await secretsManager.listSecrets(); + + // If our test secret does not exist, abort the execution. + if (secrets.filter((s) => s.name === testSecretName).length == 0) { + exec.test.abort('test secret not found'); + } + + // Let's get it and print its content + const downloadedSecret = await secretsManager.getSecret(testSecretName); + console.log(downloadedSecret.secret); +} +``` + +_A k6 script that will query the user's secrets and print a test secret's value_ + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SignatureV4/00 presign().md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SignatureV4/00 presign().md new file mode 100644 index 0000000000..dfc9f3a2a3 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SignatureV4/00 presign().md @@ -0,0 +1,199 @@ +--- +title: 'presign' +description: 'Signaturev4.presign pre-signs a URL with the AWS Signature V4 algorithm' +excerpt: 'SignatureV4.sign pre-signs a URL with the AWS Signature V4 algorithm' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/signaturev4/presign/ +--- + +`SignatureV4.presign()` pre-signs a URL with the AWS Signature V4 algorithm. Given an HTTP request description, it returns a new HTTP request with the AWS signature v4 authorization added. It returns an Object holding a `url` containing the authorization information encoded in its query string, ready to use in the context of a k6 HTTP call. + +### Parameters + +The first parameter of the `presign` method consists of an Object with the following properties. + +| Property | Type | Description | +| :------------ | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| method | string | The HTTP method of the request | +| protocol | `http` or `https` string | The network protocol of the request | +| hostname | string | The hostname the request is sent to | +| path | string | The path of the request | +| headers | Object | The headers of the HTTP request | + +You can provide further options and override SignatureV4 options in the context of this specific request. +To do this, pass a second parameter to the `presign` method, which is an Object with the following parameters. + +| Property | Type | Description | +| :---------------- | :------------ | :------------------------------------------------------------------------- | +| expiresIn | number | The number of seconds before the pre-signed URL expires | +| signingDate | Date | overrides the Date used in the signing operation | +| signingService | string | overrides the signer's AWS service in the context of the `sign` operation. | +| signingRegion | string | overrides the signer's AWS region in the context of the `sign` operation | +| unsignableHeaders | `Set` | excludes headers from the signing process | +| signableHeaders | `Set` | mark headers as signed | + +### Returns + +The `presign` operation returns an Object with the following properties. + +| Property | Type | Description | +| :------- | :----- | :------------------------------------------------------------------------- | +| headers | Object | The pre-signed request headers to use in the context of a k6 HTTP request | +| url | string | The pre-signed url to use in the context of a k6 HTTP request | + +### Example + + + +```javascript +import http from 'k6/http' +import { check } from 'k6' + +import { + AWSConfig, + SignatureV4, + AMZ_CONTENT_SHA256_HEADER, + UNSIGNED_PAYLOAD, +} from 'https://jslib.k6.io/aws/0.11.0/kms.js' + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}) + +export default function () { + // In order to be able to produce pre-signed URLs, + // we need to instantiate a SignatureV4 object. + const signer = new SignatureV4({ + service: 's3', + region: awsConfig.region, + credentials: { + accessKeyId: awsConfig.accessKeyId, + secretAccessKey: awsConfig.secretAccessKey, + sessionToken: awsConfig.sessionToken, + }, + uriEscapePath: false, + applyChecksum: false, + }) + + // We can now use the signer to produce a pre-signed URL. + const signedRequest = signer.presign( + /** + * HTTP request description + */ + { + /** + * The HTTP method we will use in the request. + */ + method: 'GET', + + /** + * The network protocol we will use to make the request. + */ + protocol: 'https', + + /** + * The hostname of the service we will be making the request to. + */ + hostname: 'my-bucket.s3.us-east-1.amazonaws.com', + + /** + * The path of the request. + */ + path: '/my-file.txt', + + /** + * The headers we will be sending in the request. + * + * Note that in the specific case of this example, requesting + * an object from S3, we want to set the `x-amz-content-sha256` + * header to `UNSIGNED_PAYLOAD`. That way, we bypass the payload + * hash calculation, and communicate that value instead, as specified. + */ + headers: { [AMZ_CONTENT_SHA256_HEADER]: 'UNSIGNED-PAYLOAD' }, + }, + + /** + * (optional) pre-sign operation options. + */ + { + /** + * The number of seconds before the pre-signed URL expires + */ + expiresIn: 86400, + + /** + * A set of strings whose representing headers that should not be hoisted + * to pre-signed request's query string. If not supplied, the pre-signer + * moves all the AWS-specific headers (starting with `x-amz-`) to the request + * query string. If supplied, these headers remain in the pre-signed request's + * header. + * All headers in the provided request will have their names converted to + * lower case and then checked for existence in the unhoistableHeaders set. + * + * In the case of pre-signing S3 URLs, the body needs to be empty. + * however, the AMZ_CONTENT_SHA256_HEADER needs to be set to + * UNSIGNED_PAYLOAD. To do this, we need to set the header, + * but declare it as unhoistable, and unsignable. + */ + unhoistableHeaders: new Set([AMZ_CONTENT_SHA256_HEADER]), + + /** + * A set of strings whose members represents headers that cannot be signed. + * All headers in the provided request will have their names converted to + * lower case and then checked for existence in the unsignableHeaders set. + * + * In the case of pre-signing S3 URLs, the body needs to be empty. + * however, the AMZ_CONTENT_SHA256_HEADER needs to be set to + * UNSIGNED_PAYLOAD. To do this, we need to set the header, + * but declare it as unhoistable, and unsignable. + */ + unsignableHeaders: new Set([AMZ_CONTENT_SHA256_HEADER]), + + /** + * A set of strings whose members represents headers that should be signed. + * Any values passed here will override those provided via unsignableHeaders, + * allowing them to be signed. + * + * All headers in the provided request will have their names converted to + * lower case before signing. + */ + signableHeaders: new Set(), + + /** + * The date and time to be used as signature metadata. This value should be + * a Date object, a unix (epoch) timestamp, or a string that can be + * understood by the JavaScript `Date` constructor.If not supplied, the + * value returned by `new Date()` will be used. + */ + signingDate: new Date(), + + /** + * The service signing name. It will override the service name of the signer + * in current invocation + */ + signingService: 's3', + + /** + * The signingRegion and signingService options let the user + * specify a different region or service to pre-sign the request for. + */ + signingRegion: 'us-east-1', + } + ) + + console.log(`presigned URL: ${signedRequest.url}`) + + /** + * Our URL is now ready to be used. + */ + const res = http.get(signedRequest.url, { + headers: signedRequest.headers, + }) + + check(res, { 'status is 200': (r) => r.status === 200 }) +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SignatureV4/00 sign().md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SignatureV4/00 sign().md new file mode 100644 index 0000000000..76b0425b2d --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SignatureV4/00 sign().md @@ -0,0 +1,143 @@ +--- +title: 'sign' +description: 'Signaturev4.sign signs an HTTP request with the AWS Signature V4 algorithm' +excerpt: 'SignatureV4.sign signs an HTTP request with the AWS Signature V4 algorithm' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/signaturev4/sign/ +--- + +`SignatureV4.sign()` signs an HTTP request with the AWS Signature V4 algorithm. Given an HTTP request description, it returns a new HTTP request with the AWS signature v4 protocol headers added. It returns an Object holding a `url` and a `headers` properties, ready to use in the context of k6's HTTP call. + +### Parameters + +The first parameter of the `sign` method consists of an Object with the following properties. + +| Property | Type | Description | +| :------------ | :----------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| method | string | The HTTP method of the request | +| protocol | `http` or `https` string | The network protocol of the request | +| hostname | string | The hostname the request is sent to | +| path | string | The path of the request | +| headers | Object | The headers of the HTTP request | +| body (optional) | string or ArrayBuffer | The optional body of the HTTP request | +| query (optional) | `Object.>` | The optional query parameters of the HTTP request | + + +You can override SignatureV4 options in the context of this specific request. To do this, pass a second parameter to the `sign` method, which is an Object with the following parameters. + +| Property | Type | Description | +| :---------------- | :---------- | :------------------------------------------------------------------------- | +| signingDate | Date | overrides the Date used in the signing operation | +| signingService | string | overrides the signer's AWS service in the context of the `sign` operation. | +| signingRegion | string | overrides the signer's AWS region in the context of the `sign` operation | +| unsignableHeaders | `Set` | excludes headers from the signing process | +| signableHeaders | `Set` | mark headers as signed | + +### Returns + +| Property | Type | Description | +| :------- | :----- | :---------------------------------------------------------------------- | +| headers | Object | The signed request's headers to use in the context of a k6 HTTP request | +| url | string | The signed url to use in the context of a k6 HTTP request | + +### Example + + + +```javascript +import http from 'k6/http' + +import { AWSConfig, SignatureV4 } from 'https://jslib.k6.io/aws/0.11.0/signature.js' + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}) + +export default function () { + /** + * In order to be able to sign an HTTP request's, + * we need to instantiate a SignatureV4 object. + */ + const signer = new SignatureV4({ + service: 's3', + region: awsConfig.region, + credentials: { + accessKeyId: awsConfig.accessKeyId, + secretAccessKey: awsConfig.secretAccessKey, + sessionToken: awsConfig.sessionToken, + }, + uriEscapePath: false, + applyChecksum: false, + }) + + /** + * The sign operation will return a new HTTP request with the + * AWS signature v4 protocol headers added. It returns an Object + * implementing the SignedHTTPRequest interface, holding a `url` and a `headers` + * properties, ready to use in the context of k6's http call. + */ + const signedRequest = signer.sign( + /** + * HTTP request description + */ + { + /** + * The HTTP method we will use in the request. + */ + method: 'GET', + + /** + * The network protocol we will use to make the request. + */ + protocol: 'https', + + /** + * The hostname of the service we will be making the request to. + */ + hostname: 'mybucket.s3.us-east-1.amazonaws.com', + + /** + * The path of the request. + */ + path: '/myfile.txt', + + /** + * The headers we will be sending in the request. + */ + headers: {}, + }, + + /** + * (optional) Signature operation options allows to override the + * SignatureV4's options in the context of this specific request. + */ + { + /** + * The date and time to be used as signature metadata. This value should be + * a Date object, a unix (epoch) timestamp, or a string that can be + * understood by the JavaScript `Date` constructor.If not supplied, the + * value returned by `new Date()` will be used. + */ + signingDate: new Date(), + + /** + * The service signing name. It will override the service name of the signer + * in current invocation + */ + signingService: 's3', + + /** + * The region name to sign the request. It will override the signing region of the + * signer in current invocation + */ + signingRegion: 'us-east-1', + } + ) + + http.get(signedRequest.url, { headers: signedRequest.headers }) +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SystemsManagerClient/00 getParameter.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SystemsManagerClient/00 getParameter.md new file mode 100644 index 0000000000..9e63fc9eb9 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SystemsManagerClient/00 getParameter.md @@ -0,0 +1,65 @@ +--- +title: 'SystemsManagerClient.getParameter()' +description: "SystemsManagerClient.getParameter gets a Systems Manager parameter in the caller's AWS account and region" +excerpt: "SystemsManagerClient.getParameter gets a Systems Manager parameter in the caller's AWS account and region" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/systemsmanagerclient/getparameter/ +--- + +`SystemsManagerClient.getParameter` gets a Systems Manager parameter in the caller's AWS account and region. + +### Returns + +| Type | Description | +| :---------------------------------------------------------- | :------------------------------------------------------------------------ | +| [`Promise`](/javascript-api/jslib/aws/systemsmanagerclient/systemsmanagerparameter/) | A Promise that fulfills with an array of [`SystemsManagerParameter`](/javascript-api/jslib/aws/systemsmanagerclient/systemsmanagerparameter/) objects. | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SystemsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/ssm.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const systemsManager = new SystemsManagerClient(awsConfig); +const testParameterName = 'jslib-test-parameter'; +const testParameterValue = 'jslib-test-value'; +const testParameterSecretName = 'jslib-test-parameter-secret'; +// this value was created with --type SecureString +const testParameterSecretValue = 'jslib-test-secret-value'; + +export default async function () { + // Currently the parameter needs to be created before hand + + // Let's get its value + // getParameter returns a parameter object: e.g. {name: string, value: string...} + const parameter = await systemsManager.getParameter(testParameterName); + if (parameter.value !== testParameterValue) { + exec.test.abort('test parameter not found'); + } + + // Let's get the secret value with decryption + // destructure the parameter object to get to the values you want + const { value: encryptedParameterValue } = await systemsManager.getParameter( + testParameterSecretName, + true + ); + if (encryptedParameterValue !== testParameterSecretValue) { + exec.test.abort('encrypted test parameter not found'); + } +} +``` + +_A k6 script querying a user's Systems Manager Service parameter_ + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SystemsManagerClient/90 SystemsManagerParameter.md b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SystemsManagerClient/90 SystemsManagerParameter.md new file mode 100644 index 0000000000..b51a8d597a --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/01 aws/SystemsManagerClient/90 SystemsManagerParameter.md @@ -0,0 +1,69 @@ +--- +title: 'SystemsManagerParameter' +description: 'SystemsManagerParameter is returned by the SystemsManagerClient.* methods that query parameters' +excerpt: 'SystemsManagerParameter is returned by the SystemsManagerClient.* methods that query KMS parameters' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/aws/systemsmanagerclient/systemsmanagerparameter/ +--- + +`SystemsManagerParameter.*` methods querying the Systems Manager Service parameters return some `SystemsManagerParameter` instances. Namely, `getParameter` returns an array of `SystemsManagerParameter` objects. The `SystemsManagerParameter` object describes an Amazon Systems Manager Service parameter. + +| Name | Type | Description | +| :----------------------------------------- | :----- | :------------------------------------------------------------------------------------ | +| `SystemsManagerParameter.arn` | string | The Amazon Resource Name (ARN) of the parameter | +| `SystemsManagerParameter.dataType` | string | The data type of the parameter, such as text or aws:ec2:image. The default is text. | +| `SystemsManagerParameter.lastModifiedDate` | number | Date the parameter was last changed or updated and the parameter version was created. | +| `SystemsManagerParameter.name` | string | The friendly name of the parameter. | +| `SystemsManagerParameter.selector` | string | Either the version number or the label used to retrieve the parameter value | +| `SystemsManagerParameter.sourceResult` | string | The raw result or response from the source. | +| `SystemsManagerParameter.type` | string | The type of parameter | +| `SystemsManagerParameter.value` | string | The parameter value | +| `SystemsManagerParameter.version` | string | The parameter version | + +### Example + + + +```javascript +import exec from 'k6/execution'; + +import { AWSConfig, SystemsManagerClient } from 'https://jslib.k6.io/aws/0.11.0/ssm.js'; + +const awsConfig = new AWSConfig({ + region: __ENV.AWS_REGION, + accessKeyId: __ENV.AWS_ACCESS_KEY_ID, + secretAccessKey: __ENV.AWS_SECRET_ACCESS_KEY, + sessionToken: __ENV.AWS_SESSION_TOKEN, +}); + +const systemsManager = new SystemsManagerClient(awsConfig); +const testParameterName = 'jslib-test-parameter'; +const testParameterValue = 'jslib-test-value'; +const testParameterSecretName = 'jslib-test-parameter-secret'; +// this value was created with --type SecureString +const testParameterSecretValue = 'jslib-test-secret-value'; + +export default async function () { + // Currently the parameter needs to be created before hand + + // Let's get its value + // getParameter returns a parameter object: e.g. {name: string, value: string...} + const parameter = await systemsManager.getParameter(testParameterName); + if (parameter.value !== testParameterValue) { + exec.test.abort('test parameter not found'); + } + + // Let's get the secret value with decryption + // destructure the parameter object to get to the values you want + const { value: encryptedParameterValue } = await systemsManager.getParameter( + testParameterSecretName, + true + ); + if (encryptedParameterValue !== testParameterSecretValue) { + exec.test.abort('encrypted test parameter not found'); + } +} +``` + +_A k6 script querying a user Systems Manager Service parameter_ + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx.md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx.md new file mode 100644 index 0000000000..b935bd81b4 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx.md @@ -0,0 +1,118 @@ +--- +title: "httpx" +excerpt: "httpx is a wrapper library around the native k6 http module" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/ +--- + +The `httpx` module is an external JavaScript library that wraps around the native [k6/http](/javascript-api/k6-http) module. +It's a http client with features that are not yet available in the native module. + - ability to set http options globally (such as timeout) + - ability to set default tags and headers that will be used for all requests + - more user-friendly arguments to request functions (get, post, put take the same arguments) + + +httpx module integrates well with the expect library. + + +The source code is [on GitHub](https://github.com/k6io/k6-jslib-httpx). +Please request features and report bugs through [GitHub issues](https://github.com/k6io/k6-jslib-httpx/issues). + +
+ +**This library is in active development.** + +This library is stable enough to be useful, but pay attention to the new versions released on [jslib.k6.io](https://jslib.k6.io). + +This documentation is for the only last version only. If you discover that some of the following doesn't work, you might be using an older version. + +
+ + +### Methods + +| Function | Description | +|-----------------------------------------------------------------------------------------|-------------------------------------------------------------------| +| [asyncRequest(method, url, [body], [params])](/javascript-api/jslib/httpx/asyncrequest) | Generic method for making arbitrary, asynchronous HTTP requests. | +| [request(method, url, [body], [params])](/javascript-api/jslib/httpx/request) | Generic method for making arbitrary HTTP requests. | +| [get(url, [body], [params])](/javascript-api/jslib/httpx/get) | Makes GET request | +| [post(url, [body], [params])](/javascript-api/jslib/httpx/post) | Makes POST request | +| [put(url, [body], [params])](/javascript-api/jslib/httpx/put) | Makes PUT request | +| [patch(url, [body], [params])](/javascript-api/jslib/httpx/patch) | Makes PATCH request | +| [delete(url, [body], [params])](/javascript-api/jslib/httpx/delete) | Makes DELETE request | +| [batch(requests)](/javascript-api/jslib/httpx/batch) | Batches multiple HTTP requests together to issue them in parallel. | +| [setBaseUrl(url)](/javascript-api/jslib/httpx/setbaseurl) | Sets the base URL for the session | +| [addHeader(key, value)](/javascript-api/jslib/httpx/addheader) | Adds a header to the session | +| [addHeaders(object)](/javascript-api/jslib/httpx/addheaders) | Adds multiple headers to the session | +| [clearHeader(name)](/javascript-api/jslib/httpx/clearheader) | Removes header from the session | +| [addTag(key, value)](/javascript-api/jslib/httpx/addtag) | Adds a tag to the session | +| [addTags(object)](/javascript-api/jslib/httpx/addtags) | Adds multiple tags to the session | +| [clearTag(name)](/javascript-api/jslib/httpx/cleartag) | Removes tag from the session | + + + + +### Example + + + +```javascript +import { fail } from 'k6'; +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; +import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +const USERNAME = `user${randomIntBetween(1, 100000)}@example.com`; // random email address +const PASSWORD = 'superCroc2021'; + +const session = new Httpx({ + baseURL: 'https://test-api.k6.io', + headers: { + 'User-Agent': 'My custom user agent', + 'Content-Type': 'application/x-www-form-urlencoded', + }, + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const registrationResp = session.post(`/user/register/`, { + first_name: 'Crocodile', + last_name: 'Owner', + username: USERNAME, + password: PASSWORD, + }); + + if (registrationResp.status !== 201) { + fail('registration failed'); + } + + const loginResp = session.post(`/auth/token/login/`, { + username: USERNAME, + password: PASSWORD, + }); + + if (loginResp.status !== 200) { + fail('Authentication failed'); + } + + const authToken = loginResp.json('access'); + + // set the authorization header on the session for the subsequent requests. + session.addHeader('Authorization', `Bearer ${authToken}`); + + const payload = { + name: `Croc Name`, + sex: 'M', + date_of_birth: '2019-01-01', + }; + + // this request uses the Authorization header set above. + const respCreateCrocodile = session.post(`/my/crocodiles/`, payload); + + if (respCreateCrocodile.status !== 201) { + fail('Crocodile creation failed'); + } else { + console.log('New crocodile created'); + } +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/08 asyncRequest(method, url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/08 asyncRequest(method, url, [body], [params]).md new file mode 100644 index 0000000000..3448c14e76 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/08 asyncRequest(method, url, [body], [params]).md @@ -0,0 +1,55 @@ +--- +title: 'asyncRequest(method, url, [body], [params])' +head_title: 'httpx.asyncRequest()' +description: 'Generic method for making asynchronous HTTP requests' +excerpt: 'Generic method for making asynchronous HTTP requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/asyncrequest/ +--- + +Generic method for making arbitrary asynchronous HTTP requests. +Note, this method returns a Promise. You must use the `await` keyword to resolve it. + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| method | string | HTTP method. Must be uppercase (GET, POST, PUT, PATCH, OPTIONS, HEAD, etc) | +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects will be `x-www-form-urlencoded`. Set to `null` to omit the body. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + + +### Returns + +| Type | Description | +|-----------------------|------------------------------------------------------------| +| Promise with Response | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default async function testSuite() { + const resp_get = await session.asyncRequest('GET', `/status/200`); + const resp_post = await session.asyncRequest('POST', `/status/200`, { key: 'value' }); + const resp_put = await session.asyncRequest('PUT', `/status/200`, { key: 'value' }); + const resp_patch = await session.asyncRequest('PATCH', `/status/200`, { key: 'value' }); + const resp_delete = await session.asyncRequest('DELETE', `/status/200`); + + // specific methods are also available. + const respGet = await session.asyncGet(`/status/200`); + const respPost = await session.asyncPost(`/status/200`, { key: 'value' }); + const respPut = await session.asyncPut(`/status/200`, { key: 'value' }); + const respPatch = await session.asyncPatch(`/status/200`, { key: 'value' }); + const respDelete = await session.asyncDelete(`/status/200`); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/09 request(method, url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/09 request(method, url, [body], [params]).md new file mode 100644 index 0000000000..c0c0b59710 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/09 request(method, url, [body], [params]).md @@ -0,0 +1,50 @@ +--- +title: 'request(method, url, [body], [params])' +head_title: 'httpx.request()' +description: 'Generic method for making arbitrary HTTP requests' +excerpt: 'Generic method for making arbitrary HTTP requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/request/ +--- + +Generic method for making arbitrary HTTP requests. + +Consider using specific methods for making common requests ([get](/javascript-api/jslib/httpx/get), [post](/javascript-api/jslib/httpx/post), [put](/javascript-api/jslib/httpx/put), [patch](/javascript-api/jslib/httpx/patch)) + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| method | string | HTTP method. Must be uppercase (GET, POST, PUT, PATCH, OPTIONS, HEAD, etc) | +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects are `x-www-form-urlencoded`. To omit body, set to `null`. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp_get = session.request('GET', `/status/200`); + const resp_post = session.request('POST', `/status/200`, { key: 'value' }); + const resp_put = session.request('PUT', `/status/200`, { key: 'value' }); + const resp_patch = session.request('PATCH', `/status/200`, { key: 'value' }); + const resp_delete = session.request('DELETE', `/status/200`); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/10 get(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/10 get(url, [body], [params]).md new file mode 100644 index 0000000000..64232c1287 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/10 get(url, [body], [params]).md @@ -0,0 +1,40 @@ +--- +title: 'get(url, [body], [params])' +description: 'httpx.get makes GET requests' +excerpt: 'httpx.get makes GET requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/get/ +--- + +`session.get(url, body, params)` makes a GET request. Only the URL parameter is required + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Set to `null` to omit the body. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +| -------------------------------------------- |-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://test-api.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.get(`/public/crocodiles/`); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/11 post(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/11 post(url, [body], [params]).md new file mode 100644 index 0000000000..8035ceb280 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/11 post(url, [body], [params]).md @@ -0,0 +1,45 @@ +--- +title: 'post(url, [body], [params])' +head_title: 'httpx.post' +description: 'httpx.post makes POST requests' +excerpt: 'httpx.post makes POST requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/post/ +--- + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects are `x-www-form-urlencoded`. To omit body, set to `null` . | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +|----------------------------------------------|-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://test-api.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.post(`/user/register/`, { + first_name: 'Mr', + last_name: 'Croco', + username: 'my user', + password: 'my password', + }); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/12 put(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/12 put(url, [body], [params]).md new file mode 100644 index 0000000000..a639d731e9 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/12 put(url, [body], [params]).md @@ -0,0 +1,48 @@ +--- +title: 'put(url, [body], [params])' +head_title: 'httpx.put' +description: 'httpx.put makes PUT requests' +excerpt: 'httpx.put makes PUT requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/put/ +--- + +`session.put(url, body, params)` makes a PUT request. Only the first parameter is required + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects are `x-www-form-urlencoded`. To omit body, set to `null`. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +|----------------------------------------------|-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.put(`/put`, { + first_name: 'Mr', + last_name: 'Croco', + username: 'my user', + password: 'my password', + }); + console.log(resp.status); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/13 patch(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/13 patch(url, [body], [params]).md new file mode 100644 index 0000000000..284dc5ee54 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/13 patch(url, [body], [params]).md @@ -0,0 +1,47 @@ +--- +title: 'patch(url, [body], [params])' +head_title: 'httpx.patch' +description: 'httpx.patch makes PATCH requests' +excerpt: 'httpx.patch makes PATCH requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/patch/ +--- + +`session.patch(url, body, params)` makes a PATCH request. Only the first parameter is required + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects are `x-www-form-urlencoded`. To omit body, set to `null` . | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +|----------------------------------------------|-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.patch(`/patch`, { + first_name: 'Mr', + last_name: 'Croco', + username: 'my user', + password: 'my password', + }); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/14 delete(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/14 delete(url, [body], [params]).md new file mode 100644 index 0000000000..9957abce3d --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/14 delete(url, [body], [params]).md @@ -0,0 +1,41 @@ +--- +title: 'delete(url, [body], [params])' +description: 'httpx.delete makes DELETE requests' +excerpt: 'httpx.delete makes DELETE requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/delete/ +--- + +`session.delete(url, body, params)` makes a DELETE request. Only the first parameter is required. Body is discouraged. + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects will be `x-www-form-urlencoded`. Set to `null` to omit the body. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +|----------------------------------------------|-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.delete(`/delete`); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/15 options(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/15 options(url, [body], [params]).md new file mode 100644 index 0000000000..6657b4880d --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/15 options(url, [body], [params]).md @@ -0,0 +1,42 @@ +--- +title: 'options(url, [body], [params])' +description: 'httpx.options makes OPTIONS requests' +excerpt: 'httpx.options makes OPTIONS requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/options/ +--- + +`session.options(url, body, params)` makes an OPTIONS request. Only the first parameter is required + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects are `x-www-form-urlencoded`. To omit the body, set to `null`. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +|----------------------------------------------|-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.options(`/options`); + console.log(resp.status); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/16 head(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/16 head(url, [body], [params]).md new file mode 100644 index 0000000000..ae5aecc63d --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/16 head(url, [body], [params]).md @@ -0,0 +1,42 @@ +--- +title: 'head(url, [body], [params])' +description: 'httpx.head makes HEAD requests' +excerpt: 'httpx.head makes HEAD requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/head/ +--- + +`session.head(url, body, params)` makes a HEAD request. Only the first parameter is required + + +| Parameter | Type | Description | +| -------------- | ------ | ------------------------------------------------------------------------------------ | +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects will be `x-www-form-urlencoded`. Set to `null` to omit the body. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +| -------------------------------------------- | --------------------- | +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.head(`/head`); + console.log(resp.status); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/17 trace(url, [body], [params]).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/17 trace(url, [body], [params]).md new file mode 100644 index 0000000000..84c22d6302 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/17 trace(url, [body], [params]).md @@ -0,0 +1,42 @@ +--- +title: 'trace(url, [body], [params])' +description: 'httpx.trace makes TRACE requests' +excerpt: 'httpx.trace makes TRACE requests' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/trace/ +--- + +`session.trace(url, body, params)` makes a TRACE request. Only the first parameter is required + + +| Parameter | Type | Description | +|-------------------|-------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| +| url | string | HTTP URL. If baseURL is set, provide only path. | +| body (optional) | null / string / object / ArrayBuffer / [SharedArray](/javascript-api/k6-data/sharedarray) | Request body; objects will be `x-www-form-urlencoded`. Set to `null` to omit the body. | +| params (optional) | null or object {} | Additional [parameters](/javascript-api/k6-http/params) for this specific request. | + +### Returns + +| Type | Description | +|----------------------------------------------|-----------------------------------------------------------| +| [Response](/javascript-api/k6-http/response) | HTTP [Response](/javascript-api/k6-http/response) object. | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ + baseURL: 'https://httpbin.test.k6.io', + timeout: 20000, // 20s timeout. +}); + +export default function testSuite() { + const resp = session.trace(`/trace`); + console.log(resp.status); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/19 batch(requests).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/19 batch(requests).md new file mode 100644 index 0000000000..4c44a8e702 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/19 batch(requests).md @@ -0,0 +1,61 @@ +--- +title: 'batch( requests )' +head_title: 'httpx.batch(requests)' +description: 'Issue multiple HTTP requests in parallel (like e.g. browsers tend to do).' +excerpt: 'Issue multiple HTTP requests in parallel (like e.g. browsers tend to do).' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/batch/ +--- + +Batch multiple HTTP requests together, to issue them in parallel over multiple TCP connections. + +| Parameter | Type | Description | +|-------------------|--------------|-------------------------------------------------------------| +| requests | array | An array containing requests, in string or object form | +| params (optional) | object | Additional parameters for all requests in the batch | + + +### Returns + +| Type | Description | +|-------|---------------------------------------------------------------------------| +| array | An array containing [Response](/javascript-api/k6-http/response) objects. | + +### Example + + + +```javascript +import { Httpx, Get } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; +import { describe } from 'https://jslib.k6.io/expect/0.0.4/index.js'; + +const session = new Httpx({ baseURL: 'https://test-api.k6.io' }); + +export default function () { + describe('01. Fetch public crocodiles all at once', (t) => { + const responses = session.batch( + [ + new Get('/public/crocodiles/1/'), + new Get('/public/crocodiles/2/'), + new Get('/public/crocodiles/3/'), + new Get('/public/crocodiles/4/'), + ], + { + tags: { name: 'PublicCrocs' }, + } + ); + + responses.forEach((response) => { + t.expect(response.status) + .as('response status') + .toEqual(200) + .and(response) + .toHaveValidJson() + .and(response.json('age')) + .as('croc age') + .toBeGreaterThan(7); + }); + }); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/20 setBaseUrl(url).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/20 setBaseUrl(url).md new file mode 100644 index 0000000000..ccc7049695 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/20 setBaseUrl(url).md @@ -0,0 +1,30 @@ +--- +title: 'setBaseUrl( url )' +description: 'sets the base URL for the session' +excerpt: 'sets the base URL for the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/setbaseurl/ +--- + + +| Parameter | Type | Description | +|-------------|--------------|------------------------------------------------------------| +| baseURL | string | Base URL to be used for all requests issued in the session | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx(); + +session.setBaseUrl('https://test-api.k6.io'); + +export default function () { + session.get('/public/crocodiles/1/'); // baseUrl doesn't need to be repeated on every request +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/21 addHeader(key, value).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/21 addHeader(key, value).md new file mode 100644 index 0000000000..8eecf55a68 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/21 addHeader(key, value).md @@ -0,0 +1,31 @@ +--- +title: 'addHeader( key, value )' +description: 'adds a header to the session' +excerpt: 'adds a header to the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/addheader/ +--- + + +| Parameter | Type | Description | +|------------|--------------|------------------------------| +| name | string | Header name | +| value | string | Header value | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ baseURL: 'https://test-api.k6.io' }); + +session.addHeader('Authorization', 'token1'); + +export default function () { + session.get('/public/crocodiles/1/'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/22 addHeaders(object).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/22 addHeaders(object).md new file mode 100644 index 0000000000..e61e9d4e06 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/22 addHeaders(object).md @@ -0,0 +1,34 @@ +--- +title: 'addHeaders( object )' +description: 'adds multiple headers to the session' +excerpt: 'adds multiple headers to the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/addheaders/ +--- + + +| Parameter | Type | Description | +|-------------|--------------|----------------------------| +| headers | object | Object | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx(); + +session.addHeaders({ + 'Authorization': 'token1', + 'User-Agent': 'My custom user agent', + 'Content-Type': 'application/x-www-form-urlencoded', +}); + +export default function () { + session.get('https://test-api.k6.io/public/crocodiles/1/'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/23 clearHeader(name).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/23 clearHeader(name).md new file mode 100644 index 0000000000..f9090fcbd8 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/23 clearHeader(name).md @@ -0,0 +1,30 @@ +--- +title: 'clearHeader( name )' +description: 'removes header from the session' +excerpt: 'removes header from the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/clearheader/ +--- + + +| Parameter | Type | Description | +|-------------|-----------|-------------------------------| +| name | string | Header name to be removed | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ headers: { Authorization: 'token1' } }); + +session.clearHeader('Authorization'); // removes header set in the constructor + +export default function () { + session.get('https://test-api.k6.io/public/crocodiles/1/'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/24 addTag(key, value).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/24 addTag(key, value).md new file mode 100644 index 0000000000..8939f14bdd --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/24 addTag(key, value).md @@ -0,0 +1,32 @@ +--- +title: 'addTag( key, value )' +description: 'adds a tag to the session' +excerpt: 'adds a tag to the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/addtag/ +--- + + +| Parameter | Type | Description | +|------------|-------------|-------------------| +| name | string | Tag name | +| value | string | Tag value | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ baseURL: 'https://test-api.k6.io' }); + +session.addTag('tagName', 'tagValue'); +session.addTag('AnotherTagName', 'tagValue2'); + +export default function () { + session.get('/public/crocodiles/1/'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/25 addTags(object).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/25 addTags(object).md new file mode 100644 index 0000000000..dbbc4ef0dd --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/25 addTags(object).md @@ -0,0 +1,33 @@ +--- +title: 'addTags( object )' +description: 'adds multiple tags to the session' +excerpt: 'adds multiple tags to the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/addtags/ +--- + + +| Parameter | Type | Description | +|------------|-----------|--------------| +| headers | object | Object | + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx(); + +session.addTags({ + Tag1: 'value1', + Tag2: 'value2', + Tag3: 'value3', +}); + +export default function () { + session.get('https://test-api.k6.io/public/crocodiles/1/'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/26 clearTag(name).md b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/26 clearTag(name).md new file mode 100644 index 0000000000..5928f34b29 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/02 httpx/26 clearTag(name).md @@ -0,0 +1,30 @@ +--- +title: 'clearTag( name )' +description: 'removes tag from the session' +excerpt: 'removes tag from the session' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/httpx/cleartag/ +--- + + +| Parameter | Type | Description | +|------------|-----------|--------------------------| +| name | string | Tag name to be removed | + + +### Example + + + +```javascript +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; + +const session = new Httpx({ tags: { tagName: 'tagValue' } }); + +session.clearTag('tagName'); // removes tag set in the constructor + +export default function () { + session.get('https://test-api.k6.io/public/crocodiles/1/'); +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs.md b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs.md new file mode 100644 index 0000000000..dde20d9722 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs.md @@ -0,0 +1,84 @@ +--- +title: "k6chaijs" +excerpt: "Assertion library for k6" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/k6chaijs/ +--- + +`k6chaijs` is a library to provide BDD assertions in k6 based on [ChaiJS](https://www.chaijs.com/). You can use `k6chaijs` as an alternative to [check](/javascript-api/k6/check/) and [group](/javascript-api/k6/group/). + +With this library, you get the following: +- BDD style of assertions for more expressive language +- chainable assertions +- more powerful assertions functions such as: `deep`, `nested`, `ordered`, etc. +- automatic assertion messages +- [exception handling](/javascript-api/jslib/k6chaijs/error-handling/) for better test stability + + +## Installation + +There's nothing to install. This library is hosted on [jslib](https://jslib.k6.io/) and can be imported in the k6 script directly. + + + + +```javascript +import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; +``` + + + +Alternatively, you can use a copy of this file stored locally. The source code is available on [GitHub](https://github.com/grafana/k6-jslib-k6chaijs). + +## Example + +The following example tests a hypothetical HTTP API that returns a JSON array of objects. Copy the following code, and save it as `script.js`: + + + +```javascript +import http from 'k6/http'; +import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; + +export default function testSuite() { + describe('Fetch a list of public crocodiles', () => { + const response = http.get('https://test-api.k6.io/public/crocodiles'); + + expect(response.status, 'response status').to.equal(200); + expect(response).to.have.validJsonBody(); + expect(response.json().length, 'number of crocs').to.be.above(4); + }); +} +``` + + + +When you run this test with `k6 run script.js`, the output at the end of the test shows: + +```bash +█ Fetch a list of public crocodiles + ✓ expected response status to equal 200 + ✓ has valid json body + ✓ expected number of crocs to be above 4 +``` + +If you are familiar with k6, the result is the same as using [check](/javascript-api/k6/check/) and [group](/javascript-api/k6/group/). Note that [expect](/javascript-api/jslib/k6chaijs/expect/) might add or extend the assertion message. + +## API + +| API | Description | +| -------- | ----------- | +| [config](/javascript-api/jslib/k6chaijs/config/) | Options to change `k6chaijs` behaviour. | +| [describe](/javascript-api/jslib/k6chaijs/describe/) | A wrapper of [group](/javascript-api/k6/group/) that catches exceptions to allow continuing the test execution. It returns a boolean to indicate the success of all its `k6chaijs` assertions. | +| [expect](/javascript-api/jslib/k6chaijs/expect/) | A wrapper of [check](/javascript-api/k6/check/) that provides BDD style of assertions. | + + +## Plugins + +It's possible to extend the default functionality with [Chai plugins](https://www.chaijs.com/plugins/). To use a plugin or build a Chai version with plugins, follow the instructions in this [example](https://community.grafana.com/t/how-to-build-plugins-for-chaijs/97010/3). + +## Read more + +- [Using chai with k6](https://k6.io/blog/k6-chai-js/) + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/31 config.md b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/31 config.md new file mode 100644 index 0000000000..5a999f1b4c --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/31 config.md @@ -0,0 +1,54 @@ +--- +title: 'config' +excerpt: 'Global configuration options for k6Chaijs' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/k6chaijs/config/ +--- + +Chai exposes a few options to change the library configuration. + + +| Config option | Default | Description | +| ------------------------- | ----------- | ----------- | +| truncateMsgThreshold | 300 | Check message length is truncated to this value. | +| truncateVariableThreshold | 100 | Variables interpolated into check message are truncated to this length. It prevents mistakes when the check name is very large, especially when `aggregateChecks` is `false`. | +| aggregateChecks | true | The actual values are not interpolated into the check message. Disable for tests with 1 iteration. | +| logFailures | false | When the check fails, debug messages are printed. | + + + + +```javascript +import http from 'k6/http'; +import chai, { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; + +// individual variables should be up to 20 chars after rendering. +chai.config.truncateVariableThreshold = 20; + +// whole check() message must be below 300 chars. +chai.config.truncateMsgThreshold = 300; + +// the variable values (resp.status) are inserted into the check message - useful for debugging or tests with 1 iteration +chai.config.aggregateChecks = false; + +// when the check fails, WARN messages with variables are printed. Useful for debugging. +chai.config.logFailures = true; + +export default function testSuite() { + describe('Testing bad assertion.', () => { + const response = http.get('https://test-api.k6.io/'); + + expect(response.body).to.have.lengthOf.at.least(500); + }); +} +``` + + + +The resulting + +```bash +█ Testing bad assertion. + ✓ expected '\n\n\n\n + +```javascript +import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; + +export default function testSuite() { + const success1 = describe('Basic test', () => { + expect(1, 'number one').to.equal(1); + }); + console.log(success1); // true + + const success2 = describe('Another test', () => { + throw 'Something entirely unexpected happened'; + }); + console.log(success2); // false + + const success3 = describe('Yet another test', () => { + expect(false, 'my vaule').to.be.true(); + }); + console.log(success3); // false +} +``` + + + + + +```bash +default ✓ [======================================] 1 VUs 00m00.0s/10m0s 1/1 iters, 1 per VU + + █ Basic test + ✓ expected number one to equal 1 + + █ Another test + ✗ Exception raised "Something entirely unexpected happened" + ↳ 0% — ✓ 0 / ✗ 1 + + █ Yet another test + ✗ expected my vaule to be true + ↳ 0% — ✓ 0 / ✗ 1 +``` + + + + +## API + +| Parameter | Type | Description | +|-----------|----------|---------------------------------------| +| name | string | Test case name. The test case name should be unique. Otherwise, the test case will be grouped. | +| function | function | The test case function to be executed | + + +### Returns + +| Type | Description | +| ------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------| +| bool | Returns true when all `expect` conditions within the `describe()` body were successful, and no unhandled exceptions were raised, otherwise false. | + +## Chaining describe() blocks + +If you want to skip the execution of the following `describe` blocks, consider chaining them using `&&` as shown below. + + + +```javascript +import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; + +export default function testSuite() { + describe('Basic test', () => { + expect(1, 'number one').to.equal(1); + }) && + + describe('Another test', () => { + throw 'Something entirely unexpected happened'; + }) && + + describe('Yet another test', () => { + // the will not be executed because the prior block returned `false` + expect(false, 'my vaule').to.be.true(); + }) +} +``` diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/34 expect.md b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/34 expect.md new file mode 100644 index 0000000000..ab491cc870 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/34 expect.md @@ -0,0 +1,168 @@ +--- +title: 'expect()' +excerpt: 'BDD style to construct k6 assertions.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/k6chaijs/expect/ +--- + +`expect` is a wrapper of [check](/javascript-api/k6/check/) to provide BDD style of assertions in k6. It implements the [Chai Expect API](https://www.chaijs.com/api/bdd/): + + + +- [not](https://www.chaijs.com/api/bdd/#method_not) +- [deep](https://www.chaijs.com/api/bdd/#method_deep) +- [nested](https://www.chaijs.com/api/bdd/#method_nested) +- [own](https://www.chaijs.com/api/bdd/#method_own) +- [ordered](https://www.chaijs.com/api/bdd/#method_ordered) +- [any](https://www.chaijs.com/api/bdd/#method_any) +- [all](https://www.chaijs.com/api/bdd/#method_all) +- [a](https://www.chaijs.com/api/bdd/#method_a) +- [include](https://www.chaijs.com/api/bdd/#method_include) +- [ok](https://www.chaijs.com/api/bdd/#method_ok) +- [true](https://www.chaijs.com/api/bdd/#method_true) +- [false](https://www.chaijs.com/api/bdd/#method_false) +- [null](https://www.chaijs.com/api/bdd/#method_null) +- [undefined](https://www.chaijs.com/api/bdd/#method_undefined) +- [NaN](https://www.chaijs.com/api/bdd/#method_nan) +- [exist](https://www.chaijs.com/api/bdd/#method_exist) +- [empty](https://www.chaijs.com/api/bdd/#method_empty) +- [arguments](https://www.chaijs.com/api/bdd/#method_arguments) +- [equal](https://www.chaijs.com/api/bdd/#method_equal) +- [eql](https://www.chaijs.com/api/bdd/#method_eql) +- [above](https://www.chaijs.com/api/bdd/#method_above) +- [least](https://www.chaijs.com/api/bdd/#method_least) +- [below](https://www.chaijs.com/api/bdd/#method_below) +- [most](https://www.chaijs.com/api/bdd/#method_most) +- [within](https://www.chaijs.com/api/bdd/#method_within) +- [instanceof](https://www.chaijs.com/api/bdd/#method_instanceof) +- [property](https://www.chaijs.com/api/bdd/#method_property) +- [ownPropertyDescriptor](https://www.chaijs.com/api/bdd/#method_ownpropertydescriptor) +- [lengthOf](https://www.chaijs.com/api/bdd/#method_lengthOf) +- [match](https://www.chaijs.com/api/bdd/#method_match) +- [string](https://www.chaijs.com/api/bdd/#method_string) +- [keys](https://www.chaijs.com/api/bdd/#method_keys) +- [throw](https://www.chaijs.com/api/bdd/#method_throw) +- [respondTo](https://www.chaijs.com/api/bdd/#method_respondto) +- [itself](https://www.chaijs.com/api/bdd/#method_itself) +- [satisfy](https://www.chaijs.com/api/bdd/#method_satisfy) +- [closeTo](https://www.chaijs.com/api/bdd/#method_closeto) +- [members](https://www.chaijs.com/api/bdd/#method_members) +- [oneOf](https://www.chaijs.com/api/bdd/#method_oneOf) +- [change](https://www.chaijs.com/api/bdd/#method_change) +- [increase](https://www.chaijs.com/api/bdd/#method_increase) +- [decrease](https://www.chaijs.com/api/bdd/#method_decrease) +- [by](https://www.chaijs.com/api/bdd/#method_by) +- [extensible](https://www.chaijs.com/api/bdd/#method_extensible) +- [sealed](https://www.chaijs.com/api/bdd/#method_sealed) +- [frozen](https://www.chaijs.com/api/bdd/#method_frozen) +- [finite](https://www.chaijs.com/api/bdd/#method_finite) + + + + + + +```javascript +import http from "k6/http"; +import { describe, expect } from "https://jslib.k6.io/k6chaijs/4.3.4.3/index.js"; + +export default function () { + describe('Basic test', () => { + expect({ a: 1 }).to.not.have.property("b"); + expect(2).to.equal(2); + expect({ a: 1 }).to.deep.equal({ a: 1 }); + expect({ a: { b: ["x", "y"] } }).to.have.nested.property("a.b[1]"); + expect({ a: 1 }).to.have.own.property("a"); + expect([1, 2]) + .to.have.ordered.members([1, 2]) + .but.not.have.ordered.members([2, 1]); + expect({ a: 1, b: 2 }).to.not.have.any.keys("c", "d"); + expect({ a: 1, b: 2 }).to.have.all.keys("a", "b"); + expect("foo").to.be.a("string"); + expect([1, 2, 3]).to.be.an("array").that.includes(2); + expect("foobar").to.include("foo"); + expect(1).to.equal(1); + expect(true).to.be.true; + expect(false).to.be.false; + expect(null).to.be.null; + expect(undefined).to.be.undefined; + expect(NaN).to.be.NaN; + expect(1).to.equal(1); + expect([]).to.be.empty; + expect({}).not.to.be.arguments; + expect(1).to.equal(1); + expect({ a: 1 }).to.eql({ a: 1 }).but.not.equal({ a: 1 }); + expect("foo").to.have.lengthOf(3); + expect(2).to.equal(2); + expect(1).to.equal(1); + expect(2).to.be.at.most(3); + expect(2).to.equal(2); + expect({ a: 1 }).to.not.be.an.instanceof(Array); + expect({ a: 1 }).to.have.property("a"); + expect([1, 2, 3]).to.have.lengthOf(3); + expect("foobar").to.match(/^foo/); + expect("foobar").to.have.string("bar"); + expect({ a: 1, b: 2 }).to.have.all.keys("a", "b"); + const badFn = function () { + throw new TypeError("Illegal salmon!"); + }; + expect(badFn).to.throw(); + expect(1).to.satisfy(function (num) { + return num > 0; + }); + expect(1.5).to.equal(1.5); + expect([1, 2, 3]).to.have.members([2, 1, 3]); + expect("Today is sunny").to.contain.oneOf(["sunny", "cloudy"]); + expect({ a: 1 }).to.be.extensible; + expect(1).to.be.finite; + }); +} + +``` + + + +When you run this test with `k6 run script.js`, the output at the end of the test shows: + +```bash +default ✓ [======================================] 1 VUs 00m00.0s/10m0s 1/1 iters, 1 per VU + + █ Basic test + + ✓ expected ${this} to not have property 'b' + ✓ expected ${this} to equal 2 + ✓ expected ${this} to deeply equal { a: 1 } + ✓ expected ${this} to have nested property 'a.b[1]' + ✓ expected ${this} to have own property 'a' + ✓ expected ${this} to be an array + ✓ expected ${this} to have the same ordered members as [ 1, 2 ] + ✓ expected ${this} to not have the same ordered members as [ 2, 1 ] + ✓ expected ${this} to not have keys 'c', or 'd' + ✓ expected ${this} to have keys 'a', and 'b' + ✓ expected ${this} to be a string + ✓ expected ${this} to include 2 + ✓ expected ${this} to include 'foo' + ✓ expected ${this} to equal 1 + ✓ expected ${this} to be true + ✓ expected ${this} to be false + ✓ expected ${this} to be null + ✓ expected ${this} to be undefined + ✓ expected ${this} to be NaN + ✓ expected ${this} to be empty + ✓ expected ${this} to not be arguments + ✓ expected ${this} to not equal { a: 1 } + ✓ expected ${this} to have property 'length' + ✓ expected ${this} to have a length of 3 got ${actual} + ✓ expected ${this} to be at most 3 + ✓ expected ${this} to not be an instance of Array + ✓ expected ${this} to have property 'a' + ✓ expected ${this} to match /^foo/ + ✓ expected ${this} to contain 'bar' + ✓ expected ${this} to be a function + ✓ expected ${this} to throw an error + ✓ expected ${this} to satisfy [Function] + ✓ expected ${this} to equal 1.5 + ✓ expected ${this} to have the same members as [ 2, 1, 3 ] + ✓ expected ${this} to contain one of [ 'sunny', 'cloudy' ] + ✓ expected ${this} to be extensible + ✓ expected ${this} to be a finite number +``` \ No newline at end of file diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/35 error handling.md b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/35 error handling.md new file mode 100644 index 0000000000..8b2b6bd9a8 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/35 error handling.md @@ -0,0 +1,97 @@ +--- +title: 'Error handling' +excerpt: 'How to handle errors in k6chaijs.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/k6chaijs/error-handling/ +--- + +When you execute a load test, your System Under Test (SUT) may often become over saturated and start responding with errors. In this case, you need to consider what the iteration execution should do: + +1. to embrace the system error and continue the execution of the scenario +2. or to exit + +It's not uncommon for performance testers to forget about these cases. We often write fragile test code that assumes our system's response will always succeed and contain the expected data. + + + + +```javascript +import { check, group } from 'k6'; +import http from 'k6/http'; + +export default function () { + group('Fetch a list of public crocodiles', () => { + const res = http.get('https://test-api.k6.io/public/crocodiles'); + check(res, { + 'is status 200': (r) => r.status === 200, + 'got more than 5 crocs': (r) => r.json().length > 5, + }); + // ... continue test within the group... + }); + + group('other group', () => { + //... + }); +} +``` + + + + +This code will work fine when the SUT returns correct responses. But, when the SUT starts to fail, `r.json().length` will throw an exception: + +```bash +ERRO[0001] cannot parse json due to an error at line 1, character 2 , error: invalid character '<' looking for beginning of value +running at reflect.methodValueCall (native) +``` + +In this case, k6 throws a JavaScript exception and **exits the execution of the current iteration** but continues starting new iterations. + +This might not be ideal because: + +1. system errors are propagated as exceptions that are not reported on the test results +2. you might want to embrace these errors - as normal - and continue the execution + +It's possible to rewrite this test to be less fragile, but it can make our test code longer and less readable. + +# Handling exceptions + +Sometimes it's hard to predict how a SUT might fail. For those cases, [describe](/javascript-api/jslib/k6chaijs/describe/) catches any internal exceptions and: +1. records them as failed assertions +2. continues the execution (outside of its `describe()` function) + + + +```javascript +import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; + +export default function testSuite() { + describe('Test case against a Shaky SUT', (t) => { + throw 'Something entirely unexpected happened'; + }); + + // this test case will be executed because + // the previous `describe` catched the exception + describe('Another test case', (t) => { + expect(2).to.equal(2); + }); +} +``` + + + + + +```bash +█ Test case against a Shaky SUT + + ✗ Exception raised "Something entirely unexpected happened" + ↳ 0% — ✓ 0 / ✗ 1 + +█ Another test case + + ✓ expected ${this} to equal 2 +``` + + + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/describe-test-output-1.png b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/describe-test-output-1.png new file mode 100644 index 0000000000..99d95599e9 Binary files /dev/null and b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/describe-test-output-1.png differ diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/describe-test-output-2.png b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/describe-test-output-2.png new file mode 100644 index 0000000000..51028527b3 Binary files /dev/null and b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/describe-test-output-2.png differ diff --git a/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/exception-handling.png b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/exception-handling.png new file mode 100644 index 0000000000..da52928146 Binary files /dev/null and b/src/data/markdown/docs/20 jslib/01 jslib/03 k6chaijs/images/exception-handling.png differ diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils.md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils.md new file mode 100644 index 0000000000..16f98949d1 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils.md @@ -0,0 +1,60 @@ +--- +title: "utils" +excerpt: "A collection of small utility functions useful during load testing with k6. " +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/ +--- + +The `utils` module contains number of small utility functions useful in every day load testing. + +> ⭐️ Source code available on [GitHub](https://github.com/k6io/k6-jslib-utils). +> Please request features and report bugs through [GitHub issues](https://github.com/k6io/k6-jslib-utils/issues). + + + + + +| Function | Description | +| -------- | ----------- | +| [randomIntBetween(min, max)](/javascript-api/jslib/utils/randomintbetween) | Random integer in a given range | +| [randomItem(array)](/javascript-api/jslib/utils/randomitem) | Random item from a given array | +| [randomString(length, [charset])](/javascript-api/jslib/utils/randomstring) | Random string of a given length, optionally selected from a custom character set | +| [uuidv4()](/javascript-api/jslib/utils/uuidv4) | Random UUID v4 in a string representation | +| [findBetween(content, left, right, [repeat])](/javascript-api/jslib/utils/findbetween) | Extract a string between two surrounding strings | +| [normalDistributionStages(maxVUs, durationSeconds, [numberOfStages])](/javascript-api/jslib/utils/normaldistributionstages) | Creates [stages](/using-k6/options/#stages) which will produce a normal distribution (bell-curve) of VUs for a test | +| getCurrentStageIndex | Get the index of the running stage as defined in the `stages` array options. It can be used only with the executors that support the `stages` option as [ramping-vus](/using-k6/scenarios/executors/ramping-vus) or [ramping-arrival-rate](/using-k6/scenarios/executors/ramping-arrival-rate). | +| tagWithCurrentStageIndex | Tag all the generated metrics in the iteration with the index of the current running stage. | +| tagWithCurrentStageProfile | Tag all the generated metrics in the iteration with the computed profile for the current running stage. | + +## Simple example + + + +```javascript +import { sleep } from 'k6'; +import http from 'k6/http'; + +import { + randomIntBetween, + randomString, + randomItem, + uuidv4, + findBetween, +} from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'; + +export default function () { + const res = http.post(`https://test-api.k6.io/user/register/`, { + first_name: randomItem(['Joe', 'Jane']), // random name + last_name: `Jon${randomString(1, 'aeiou')}s`, //random character from given list + username: `user_${randomString(10)}@example.com`, // random email address, + password: uuidv4(), // random password in form of uuid + }); + + // find a string between two strings to grab the username: + const username = findBetween(res.body, '"username":"', '"'); + console.log('username from response: ' + username); + + sleep(randomIntBetween(1, 5)); // sleep between 1 and 5 seconds. +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils/41 randomIntBetween(min, max) copy.md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/41 randomIntBetween(min, max) copy.md new file mode 100644 index 0000000000..032106697c --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/41 randomIntBetween(min, max) copy.md @@ -0,0 +1,38 @@ +--- +title: 'randomIntBetween(min, max)' +description: 'Random integer' +excerpt: 'Random integer' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/randomintbetween/ +--- + +Function returns a random number between the specified range. The returned value is no lower than (and may possibly equal) min, and is no bigger than (and may possibly equal) max. + +| Parameter | Type | Description | +| -------------- | ------ | --- | +| min | int | Lower-end bound. Inclusive | +| max | int | Upper-end bound. Inclusive| + + +### Returns + +| Type | Description | +| ----- | --------------- | +| int | Random integer | + + +### Example + + + +```javascript +import { sleep } from 'k6'; +import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +export default function () { + // code ... + + sleep(randomIntBetween(1, 5)); // sleep between 1 and 5 seconds. +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils/42 randomItem(array).md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/42 randomItem(array).md new file mode 100644 index 0000000000..2e7bc32f9b --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/42 randomItem(array).md @@ -0,0 +1,37 @@ +--- +title: 'randomItem(array)' +description: 'Random item from an array' +excerpt: 'Random item from an array' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/randomitem/ +--- + +Function returns a random item from an array. + +| Parameter | Type | Description | +| ------------- | ------ | --- | +| arrayOfItems | array | Array [] of items | + + +### Returns + +| Type | Description | +| ----- | --------------- | +| any | Random item from the array | + + +### Example + + + +```javascript +import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +const names = ['John', 'Jane', 'Bert', 'Ed']; + +export default function () { + const randomName = randomItem(names); + console.log(`Hello, my name is ${randomName}`); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils/43 randomString(length).md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/43 randomString(length).md new file mode 100644 index 0000000000..383c9cc46b --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/43 randomString(length).md @@ -0,0 +1,43 @@ +--- +title: 'randomString(length, [charset])' +description: 'Random string' +excerpt: 'Random string' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/randomstring/ +--- + +Function returns a random string of a given length, optionally selected from a custom character set. + + +| Parameter | Type | Description | +| ------------------ | ------- | ----------- | +| length | int | Length of the random string | +| charset (optional) | string | A customized list of characters | + + +### Returns + +| Type | Description | +| ----- | --------------- | +| any | Random item(s) from the array of characters | + + +### Example + + + +```javascript +import { randomString } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +export default function () { + const randomFirstName = randomString(8); + console.log(`Hello, my first name is ${randomFirstName}`); + + const randomLastName = randomString(10, `aeioubcdfghijpqrstuv`); + console.log(`Hello, my last name is ${randomLastName}`); + + const randomCharacterWeighted = randomString(1, `AAAABBBCCD`); + console.log(`Chose a random character ${randomCharacterWeighted}`); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils/44 uuidv4().md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/44 uuidv4().md new file mode 100644 index 0000000000..676708bca4 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/44 uuidv4().md @@ -0,0 +1,36 @@ +--- +title: 'uuidv4()' +description: 'uuid v4 function' +excerpt: 'uuid v4 function' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/uuidv4/ +--- + +Function returns a random uuid v4 in a string form. + +### Parameters + +| Parameter | Type | Description | +| :---------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| secure (optional) | boolean | By default, `uuidv4()` uses a standard random number generator. If the `secure` option is set to `true`, `uuidv4` uses a cryptographically secure random number generator instead. While this adds security, the `secure` option also makes the function an order of magnitude slower. | + +### Returns + +| Type | Description | +| :----- | :-------------------- | +| string | Random UUID v4 string | + + +### Example + + + +```javascript +import { uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'; + +export default function () { + const randomUUID = uuidv4(); + console.log(randomUUID); // 35acae14-f7cb-468a-9866-1fc45713149a +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils/45 findBetween(content, left, right).md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/45 findBetween(content, left, right).md new file mode 100644 index 0000000000..580633f2a7 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/45 findBetween(content, left, right).md @@ -0,0 +1,43 @@ +--- +title: 'findBetween(content, left, right, [repeat])' +description: 'findBetween function' +excerpt: 'findBetween function' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/findbetween/ +--- + +Function that returns a string from between two other strings. + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| content | string | The string to search through (e.g. [Response.body](/javascript-api/k6-http/response/)) | +| left | string | The string immediately before the value to be extracted | +| right | string | The string immediately after the value to be extracted | +| repeat (optional) | boolean | If `true`, the result will be a string array containing all occurrences | + +### Returns + +| Type | Description | +| ----- | --------------- | +| string | The extracted string, or an empty string if no match was found. If `repeat=true`, this will be an array of strings or an empty array | + + +### Example + + + +```javascript +import { findBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +export default function () { + const response = '
Message 1
Message 2
'; + + const message = findBetween(response, '
', '
'); + + console.log(message); // Message 1 + + const allMessages = findBetween(response, '
', '
', true); + console.log(allMessages.length); // 2 +} +``` + +
diff --git a/src/data/markdown/docs/20 jslib/01 jslib/04 utils/46 normalDistributionStages(maxVus, durationSeconds, numberOfStages).md b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/46 normalDistributionStages(maxVus, durationSeconds, numberOfStages).md new file mode 100644 index 0000000000..c8939a4bcc --- /dev/null +++ b/src/data/markdown/docs/20 jslib/01 jslib/04 utils/46 normalDistributionStages(maxVus, durationSeconds, numberOfStages).md @@ -0,0 +1,44 @@ +--- +title: 'normalDistributionStages(maxVus, durationSeconds, [numberOfStages])' +description: 'normalDistributionStages function' +excerpt: 'normalDistributionStages function' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/normaldistributionstages/ +--- + +Function to create [stages](/using-k6/options/#stages) producing a _normal distribution (bell-curve)_ of VUs for a test. + +| Parameter | Type | Description | +| ------------------------- | ---- | ----------- | +| maxVus | int | Maximum virtual users at the height of the curve | +| durationSeconds | int | Overall duration for all stages combined | +| numberOfStages (optional) | int | Number of stages to create; default is `10` | + +### Returns + +| Type | Description | +| -------------- | --------------- | +| array\[object] | An array of `{"duration": "XXXs", "target": XXX}` JSON objects representing stages | + + +### Example + + + +```javascript +import { sleep } from 'k6'; +import exec from 'k6/execution'; +import { normalDistributionStages } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +export const options = { + // Alters the number of VUs from 1 to 10 over a period + // of 20 seconds comprised of 5 stages. + stages: normalDistributionStages(10, 20, 5), +}; + +export default function () { + console.log(exec.instance.vusActive); + sleep(1); +} +``` + + diff --git a/src/data/markdown/docs/20 jslib/20 jslib.md b/src/data/markdown/docs/20 jslib/20 jslib.md new file mode 100644 index 0000000000..1ad5163db5 --- /dev/null +++ b/src/data/markdown/docs/20 jslib/20 jslib.md @@ -0,0 +1,16 @@ +--- +title: "jslib" +excerpt: "External JavaScript libraries for k6" +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/jslib/ +--- + +The [jslib.k6.io](https://jslib.k6.io/) is a collection of external JavaScript libraries that can be [directly imported](/using-k6/modules#remote-http-s-modules) in k6 scripts. + + +| Library | Description | +| -------- | ----------- | +| [aws](/javascript-api/jslib/aws) | Library allowing to interact with Amazon AWS services | +| [httpx](/javascript-api/jslib/httpx) | Wrapper around [k6/http](https://k6.io/docs/javascript-api/#k6-http) to simplify session handling | +| [k6chaijs](/javascript-api/jslib/k6chaijs) | BDD assertion style | +| [utils](/javascript-api/jslib/utils) | Small utility functions useful in every day load testing | + diff --git a/src/data/markdown/docs/40 xk6-disruptor/00 About.md b/src/data/markdown/docs/40 xk6-disruptor/00 About.md new file mode 100644 index 0000000000..7953b35453 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/00 About.md @@ -0,0 +1,59 @@ +--- +title: 'About' +heading: 'xk6-disruptor Documentation' +head_title: 'xk6-disruptor Documentation' +excerpt: 'xk6-disruptor is a k6 extension providing fault injection capabilities to test system reliability under turbulent conditions.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/ +--- + +[xk6-disruptor](https://github.com/grafana/xk6-disruptor) is an extension that adds fault injection capabilities to k6. It implements the principles of the Chaos Engineering discipline to test the reliability of our applications under turbulent conditions such as delays and response errors. + +Key features include: + +- Everything as code. Facilitate test reuse and collaboration between teams without learning a new DSL. +- Fast to adopt with no day-two surprises. [No need to deploy and maintain](/javascript-api/xk6-disruptor/explanations/how-xk6-disruptor-works/) a fleet of agents or operators. +- Easy to extend and integrate with other types of k6 tests. No need to try to glue multiple tools together to get the job done. + +## Capabilities + +Currently, the disruptor is intended to test applications running in Kubernetes. Other platforms are not supported at this time. + +It provides a Javascript API to inject different [faults](/javascript-api/xk6-disruptor/api/faults/) in HTTP and gRPC requests, such as errors and delays, into the selected Kubernetes [Pods](/javascript-api/xk6-disruptor/api/poddisruptor) or [Services](/javascript-api/xk6-disruptor/api/servicedisruptor). + +Other types of faults and disruptors will be introduced in the future. The [Roadmap](https://github.com/grafana/xk6-disruptor/blob/main/ROADMAP.md) presents the project's goals for the coming months regarding new functionalities and enhancements. + + +## Use cases + +The disruptor lets you test the resiliency of distributed applications by introducing errors in the requests served by your services. + +The disruptor does not try to reproduce root causes, such as failed application instances or degraded computing or network resources. +It focuses on reproducing the side effects of such failures, so you can focus on understanding the propagation of errors between internal and public services and improving the error handling in your application. + +This way, the disruptor makes reliability tests repeatable and predictable while limiting their blast radius. +These are essentials to test applications deployed on shared infrastructures such as pre-production and testing environments. + +Common use cases are: +- Test resilient policies such as backoff, timeouts, retries, etc. +- Test the fallback functionality when internal failures arise. +- Test SLOs under common internal failures. +- Test application performance when experiencing delays. +- Add fault injection to existing performance tests. + +## Learn more + +Lear more about [Fault injection](https://k6.io/blog/democratize-chaos-testing/) and [Building Resilience early in the development cycle](https://k6.io/blog/building-resilience-early-in-the-development-cycle/). + +Check the [first steps](/javascript-api/xk6-disruptor/get-started/first-steps) to get started with the disruptor. + +Follow the [examples of injecting faults in different scenarios](/javascript-api/xk6-disruptor/examples/). + +Visit the [interactive demo environment in Killercoda](https://killercoda.com/grafana-xk6-disruptor/scenario/killercoda) and try the disruptor in a demo application without having to do any setup. + +## Contributing + +For any unexpected behavior, please search the [GitHub issues](https://github.com/grafana/xk6-disruptor/issues) first. + +And if you are interested in contributing to the development of this project, check the [contributing guide](https://github.com/grafana/xk6-disruptor/blob/main/docs/01-development/01-contributing.md). + + diff --git a/src/data/markdown/docs/40 xk6-disruptor/01 Get started.md b/src/data/markdown/docs/40 xk6-disruptor/01 Get started.md new file mode 100644 index 0000000000..472b52fc06 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/01 Get started.md @@ -0,0 +1,15 @@ +--- +title: 'Get started' +excerpt: 'xk6-disruptor is an extension that adds fault injection capabilities to k6. Start here to learn the basics and how to use the disruptor' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/get-started/ +--- + +Inject faults into kubernetes-based applications with `xk6-disruptor`. Start here to learn the basics to use the disruptor: + +- [First steps](/javascript-api/xk6-disruptor) + +- [Requirements](/javascript-api/xk6-disruptor/get-started/requirements) + +- [Installation](/javascript-api/xk6-disruptor/get-started/installation) + +- [Exposing your Kubernetes application](/javascript-api/xk6-disruptor/get-started/expose-your-application/) diff --git a/src/data/markdown/docs/40 xk6-disruptor/01 Get started/01 First steps.md b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/01 First steps.md new file mode 100644 index 0000000000..b26769105b --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/01 First steps.md @@ -0,0 +1,44 @@ +--- +title: 'First steps' +heading: 'xk6-disruptor first steps' +head_title: 'xk6-disruptor First steps' +excerpt: 'xk6-disruptor is a k6 extension providing fault injection capabilities to k6.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/first-steps/ +--- + +[xk6-disruptor](https://github.com/grafana/xk6-disruptor) is an extension that adds fault injection capabilities to k6. + +It provides a Javascript [API](/javascript-api/xk6-disruptor/api) to inject [faults](/javascript-api/xk6-disruptor/api/faults/) such as errors and delays into HTTP and gRPC requests served by selected Kubernetes [Pods](/javascript-api/xk6-disruptor/api/poddisruptor) or [Services](/javascript-api/xk6-disruptor/api/servicedisruptor). + + +```javascript +export default function () { + // Create a new disruptor that targets a service + const disruptor = new ServiceDisruptor("app-service","app-namespace"); + + // Disrupt the targets by injecting delays and faults into HTTP request for 30 seconds + const fault = { + averageDelay: '500ms', + errorRate: 0.1, + errorCode: 500 + } + disruptor.injectHTTPFaults(fault, "30s") +} +``` + +## Next steps + +Learn more about xk6-disruptor and fault injection in [About](/javascript-api/xk6-disruptor/about). + +Explore the fault injection [API](/javascript-api/xk6-disruptor/api) + +See [step-by-step examples](/javascript-api/xk6-disruptor/examples). + +Visit the [interactive demo environment](https://killercoda.com/grafana-xk6-disruptor/scenario/killercoda). + +Learn the basics of using the disruptor in your test project: + +- [Requirements](/javascript-api/xk6-disruptor/get-started/requirements) + +- [Installation](/javascript-api/xk6-disruptor/get-started/installation) + diff --git a/src/data/markdown/docs/40 xk6-disruptor/01 Get started/02 Requirements.md b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/02 Requirements.md new file mode 100644 index 0000000000..86372afc6f --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/02 Requirements.md @@ -0,0 +1,29 @@ +--- +title: 'Requirements' +excerpt: 'Requirements for using xk6-disruptor in your test scripts' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/requirements/ +--- + +The xk6-disruptor is a k6 extension. +To use it in a k6 test script, you need to bundle a k6 extension that includes the disruptor. +Refer to the [Installation](/javascript-api/xk6-disruptor/get-started/installation) section for instructions on how to get this custom build. + + xk6-disruptor needs to interact with the Kubernetes cluster on which the application under test is running. + To do so, you must have the credentials to access the cluster in a [kubeconfig](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) file. + Ensure that this file is pointed to by the `KUBECONFIG` environment variable or that it is located at the default location, `$HOME/.kube/config`. + +
+ +xk6-disruptor requires Kubernetes version 1.23 or higher + +
+ + +`xk6-disruptor` requires the [grafana/xk6-disruptor-agent](https://github.com/grafana/xk6-disruptor/pkgs/container/xk6-disruptor-agent) image for injecting the [disruptor agent](/javascript-api/xk6-disruptor/explanations/how-xk6-disruptor-works) into the disruption targets. Kubernetes clusters can be configured to restrict the download of images from public repositories. You need to ensure this image is available in the cluster where the application under test is running. Additionally, the xk6-disruptor-agent must run with network access privileges. Kubernetes clusters [can be configured to restrict the privileges of containers](https://kubernetes.io/docs/concepts/security/pod-security-admission/). +If you find an error similar to the following when using the xk6-disruptor, contact your cluster administrator and request the necessary privileges. + +> ERROR\[0000\] error creating PodDisruptor: pods "nginx" is forbidden: violates PodSecurity "baseline:latest": non-default capabilities (container "xk6-agent" must not include "NET_ADMIN", "NET_RAW" in securityContext.capabilities.add) + + +You also need to ensure your test application is accessible from the machine where the tests run. +Refer to [Expose your application](/javascript-api/xk6-disruptor/get-started/expose-your-application) section for instructions on how to make your application available from outside the Kubernetes cluster.. diff --git a/src/data/markdown/docs/40 xk6-disruptor/01 Get started/03 Installation.md b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/03 Installation.md new file mode 100644 index 0000000000..e74a5fb23d --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/03 Installation.md @@ -0,0 +1,43 @@ +--- +title: 'Installation' +excerpt: 'A step-by-step guide on how to install xk6-disruptor.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/installation/ +--- + +xk6-disruptor is a [k6 extension](/extensions). You have to run a k6 version built with the disruptor extension to use the [disruptor APIs](/javascript-api/xk6-disruptor/api/) in your k6 tests. + +The following sections explain the different options to get this custom binary. + +## Download a release binary + +The quickest way to get started is to [download a release binary from GitHub](https://github.com/grafana/xk6-disruptor/releases). + +## Build from source + +You can also use [xk6](https://github.com/grafana/xk6) to build a k6 binary. + +To find out more about how to use xk6 or what it is, check out this guide - [Build a k6 binary using Go](/extensions/guides/build-a-k6-binary-using-go/). + + +To build the k6 binary with the xk6-disruptor extension: +1. Ensure you have [Go 1.19](https://golang.org/doc/install) and [Git](https://git-scm.com/) installed. +2. Run the following commands in a terminal: + + + +```bash +# Install xk6 +go install go.k6.io/xk6/cmd/xk6@latest + +# Clone the xk6-disruptor code +git clone https://github.com/grafana/xk6-disruptor.git +cd xk6-disruptor + +# Build the custom binary +xk6 build --output xk6-disruptor --with github.com/grafana/xk6-disruptor=. +``` + + + + +xk6 will create the `xk6-disruptor` binary in the current working directory. diff --git a/src/data/markdown/docs/40 xk6-disruptor/01 Get started/04 Expose Your Application.md b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/04 Expose Your Application.md new file mode 100644 index 0000000000..719fb52679 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/04 Expose Your Application.md @@ -0,0 +1,111 @@ +--- +title: 'Expose your application' +excerpt: 'How to make your applications accessible from the test scripts.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/expose-your-application/ +--- + +To access your application from the test scripts, you must assign it an external IP in the cluster where it's running. +How you do this depends on the platform you use to deploy the application. +The following sections explain the different approaches. + + +## Using port-forwarding + +`kubectl`'s `port-forward` command allows accessing applications running in a Kubernetes cluster using a local port. + +For example, the following command will make `my-service`'s port `80` accessible as `localhost:8080`: + +```sh +kubectl port-forward svc/my-service 8080:80 +Forwarding from 127.0.0.1:8080 -> 80 +``` + +### Limitations using port forwarding + +To be able to inject faults, `xk6-disruptor` must [install an agent on each target](/javascript-api/xk6-disruptor/explanations/how-xk6-disruptor-works) that intercepts the requests and applies the desired disruptions. This process requires any existing connection to the targets to be redirected to the agent. + +Due to an existing bug in `kubectl`, the process of installing the disruptor can potentially [break the port forwarding](https://github.com/grafana/xk6-disruptor/issues/254). Notice that this issue happens only if the faults are injected in the service that is exposed using port forward. If the faults are injected in another service not exposed by port-forwarding, there shouldn't be any issue. + +Until this issue is solved in `kubectl`, tests using port forwarding to access a service should ensure the agent is installed in the targets before any traffic is sent by the test. + +The simplest way to accomplish this is to ensure the scenario that executes the load (#2) starts after the scenario that injects the faults (#1): + + + +```javascript +export const options = { + scenarios: { + disrupt: { // #1 inject faults + executor: 'shared-iterations', + iterations: 1, + vus: 1, + exec: "disrupt", + startTime: "0s", + }, + load: { // #2 execute load + executor: 'constant-arrival-rate', + rate: 100, + preAllocatedVUs: 10, + maxVUs: 100, + exec: "default", + startTime: '20s', // give time for the agents to be installed + duration: "30s", + } + } +} +``` + + + +## As a LoadBalancer service + +A service of type [`LoadBalancer`](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/) receives an external IP from an external load-balancer provider. +How you configure the load balancer depends on the your cluster's deployment platform and configuration. +The following sections provide guidelines to expose your application when running in common development environments. +If your cluster is deployed in a public cloud, check your cloud provider documentation. + +If the service that you want your tests to access is not defined as a load balancer, you can change the service type with the following command. The service will then receive an external IP. + + + +```bash +kubectl -n patch svc -p '{"spec": {"type": "LoadBalancer"}}' +``` + +```bash +kubectl -n patch svc -p '{\"spec\": {\"type\": \"LoadBalancer\"}}' +``` + + + + +You can retrieve the external IP address and store it in an environment variable (`SVC_IP` in this example) using the following command: + + + +```bash +SVC_IP=$(kubectl -n get svc --output jsonpath='{.status.loadBalancer.ingress[0].ip}') +``` + +```Powershell +$Env:SVC_IP=$(kubectl -n get svc --output jsonpath='{.status.loadBalancer.ingress[0].ip}') +``` + + + +### Configuring a LoadBalancer in Kind + +[Kind](https://kind.sigs.k8s.io/) is a tool to run local Kubernetes clusters using a Docker container to emulate nodes. +You can use kind for local development or CI. +Services deployed in a kind cluster can be exposed to be accessed from the host machine [using metallb as a load balancer](https://kind.sigs.k8s.io/docs/user/loadbalancer). + +### Configuring a LoadBalancer in Minikube + +[Minikube](https://github.com/kubernetes/minikube) implements a local Kubernetes cluster that supports different technologies to virtualize the cluster's infrastructure, such as containers, VMs or bare metal. + +Minikube's tunnel command runs as a process, creating a network route on the host to the service CIDR of the cluster. +It uses the cluster’s IP address as a gateway. The tunnel command exposes the external IP directly to any program that is running on the host operating system. + +```console +minikube tunnel +``` diff --git a/src/data/markdown/docs/40 xk6-disruptor/01 Get started/images/logo.png b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/images/logo.png new file mode 100644 index 0000000000..18a51f7aef Binary files /dev/null and b/src/data/markdown/docs/40 xk6-disruptor/01 Get started/images/logo.png differ diff --git a/src/data/markdown/docs/40 xk6-disruptor/02 Explanations.md b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations.md new file mode 100644 index 0000000000..25b3902f8d --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations.md @@ -0,0 +1,6 @@ +--- +title: 'Explanations' +excerpt: 'In-depth exploration of xk6-disruptor.' +--- + +[How xk6-disruptor works](/javascript-api/xk6-disruptor/explanations/how-xk6-disruptor-works) \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/01 How it works.md b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/01 How it works.md new file mode 100644 index 0000000000..dfea34e2d9 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/01 How it works.md @@ -0,0 +1,33 @@ +--- +title: 'How xk6-disruptor works' +excerpt: 'A brief description of the components of the xk6-disruptor and how they work when inject faults in a target system.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/how-it-works/ +--- + +xk6-disruptor consists of two main components: +- **The xk6-disruptor extension** provides a Javascript API for injecting faults into a target system using the xk6-disruptor-agent as a backend. This API is built around a collection of **disruptors**. Each disruptor targets a type of component in the system (for example Pods or cluster Nodes). +- **The xk6-disruptor-agent** injects faults into the target system where it runs. It is provided as an Docker image that you can pull from the [xk6-disruptor repository](https://github.com/grafana/xk6-disruptor/pkgs/container/xk6-disruptor-agent). + +The xk6-disruptor extension installs the agent in the target and sends commands to inject the desired faults. How this happens depends on the type of disruptor, as described in the following sections. + +## PodDisruptor + +The following diagram shows how PodDisruptor works: + +1. The PodDisruptor selects the target pods based on the selector attributes defined in the [constructor](/javascript-api/xk6-disruptor/api/poddisruptor/constructor) +2. The PodDisruptor attaches the xk6-disruptor-agent to each of the target pods +3. When a fault is injected (e.g. calling the [injectHTTTFault](/javascript-api/xk6-disruptor/api/poddisruptor/injecthttpfaults/)) the PodDisruptor sends a command to the agents to inject the fault in their respective pods + +![How PodDisruptor works](images/how-pod-disruptor-works.png) + +## ServiceDisruptor + +The ServiceDisruptor works as a wrapper around a PodDisruptor, which targets the pods that back the service. + +1. The ServiceDisruptor uses the definition of the service specified in the [constructor](/javascript-api/xk6-disruptor/api/servicedisruptor/constructor) to create a pod selector that matches the pods that back the service. +2. The ServiceDisruptor creates a PodDisruptor using this pod selector. +3. The PodDisruptor installs the agent in the target pods. + +From this point, the PodDisruptor works as described before. + +![How ServiceDisruptor works](images/how-service-disruptor-works.png) \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-pod-disruptor-works.excalidraw b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-pod-disruptor-works.excalidraw new file mode 100644 index 0000000000..a863668313 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-pod-disruptor-works.excalidraw @@ -0,0 +1,1295 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "arrow", + "version": 788, + "versionNonce": 1782377415, + "isDeleted": false, + "id": "luD1Apyt6U44VibrdCdVH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 919.6914129434699, + "y": 838.2603352046069, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 275.5265362293276, + "height": 160.26033520460703, + "seed": 1663869929, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124558470, + "link": null, + "locked": false, + "startBinding": { + "elementId": "schKhW3bFErLrOOzn_n8s", + "focus": 0.4021546701842616, + "gap": 13.191412943469913 + }, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 228.57609442771638, + -16.260335204606918 + ], + [ + 275.5265362293276, + -160.26033520460703 + ] + ] + }, + { + "type": "rectangle", + "version": 435, + "versionNonce": 355325993, + "isDeleted": false, + "id": "7xrm1RkODnRkvGU50r3Yk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 569, + "y": 345, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 241.99999999999994, + "height": 164, + "seed": 597835465, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1671124558470, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 136, + "versionNonce": 2136595175, + "isDeleted": false, + "id": "cPG1DdLtDIMbUlka1QvCI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 648, + "y": 390, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 131, + "height": 98, + "seed": 1013022121, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "PQ1dAtA3sieLGhmuz-UJ8", + "type": "arrow" + }, + { + "id": "X2pB2_fIS-DSNYmVTfabm", + "type": "arrow" + }, + { + "id": "lXN-SrvugHJjMXL8OWYoZ", + "type": "arrow" + } + ], + "updated": 1671124558470, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 220, + "versionNonce": 536013577, + "isDeleted": false, + "id": "j3cIUZW2yH8Up7_UVIc37", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 664, + "y": 411, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 50, + "seed": 1106962281, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558470, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Pod\nDisruptor", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Pod\nDisruptor" + }, + { + "type": "rectangle", + "version": 263, + "versionNonce": 1028384263, + "isDeleted": false, + "id": "Fnk162SSlBZFzwGo6HRry", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 987, + "y": 536.9938884644766, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 279.10847975553855, + "height": 159.0061115355233, + "seed": 651956809, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1671124558470, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 207, + "versionNonce": 2052235753, + "isDeleted": false, + "id": "EM1fY9kswosvD868H1fOL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1353.3915202444614, + "y": 536.9938884644766, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 279.10847975553855, + "height": 154.0061115355233, + "seed": 1880416553, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1671124558470, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 205, + "versionNonce": 51350823, + "isDeleted": false, + "id": "HsynYQv2-QRebxEqywjE3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 998.3418640183346, + "y": 572.9654316271964, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 119.33613445378151, + "height": 105.52864782276546, + "seed": 2064700425, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "VqvBGplLghDAs50Mobxrg" + } + ], + "updated": 1671124558470, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 194, + "versionNonce": 559447241, + "isDeleted": false, + "id": "VqvBGplLghDAs50Mobxrg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1012.0099312452253, + "y": 601.7297555385791, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 92, + "height": 48, + "seed": 224565065, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558470, + "link": null, + "locked": false, + "fontSize": 19.70020440608676, + "fontFamily": 1, + "text": "App\nContainer", + "baseline": 41, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HsynYQv2-QRebxEqywjE3", + "originalText": "App\nContainer" + }, + { + "type": "rectangle", + "version": 236, + "versionNonce": 470896711, + "isDeleted": false, + "id": "1YeH4cLrEZPr2GYB1IRC7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1134.44423223835, + "y": 573.4585561497327, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 119.33613445378151, + "height": 104.5423987776929, + "seed": 1808493289, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "XneuPSRMdLq5eeg_dB8vs" + }, + { + "id": "PQ1dAtA3sieLGhmuz-UJ8", + "type": "arrow" + }, + { + "id": "j3ux1Nne7J7UFkd3jt3nj", + "type": "arrow" + } + ], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 187, + "versionNonce": 1688206249, + "isDeleted": false, + "id": "XneuPSRMdLq5eeg_dB8vs", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1148.6122994652408, + "y": 601.7297555385791, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 91, + "height": 48, + "seed": 1125342311, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 19.70020440608676, + "fontFamily": 1, + "text": "Disruptor\nAgent", + "baseline": 41, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "1YeH4cLrEZPr2GYB1IRC7", + "originalText": "Disruptor\nAgent" + }, + { + "type": "rectangle", + "version": 260, + "versionNonce": 841854823, + "isDeleted": false, + "id": "BdsVEoGPm1xn3ZITvqI05", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1368.18525592055, + "y": 572.9654316271963, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 119.33613445378151, + "height": 105.52864782276546, + "seed": 1523590601, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "wuPajBq7C-e0-lXBGjQDB" + } + ], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 244, + "versionNonce": 341089929, + "isDeleted": false, + "id": "wuPajBq7C-e0-lXBGjQDB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1381.8533231474407, + "y": 601.729755538579, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 92, + "height": 48, + "seed": 1985271273, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 19.70020440608676, + "fontFamily": 1, + "text": "App\nContainer", + "baseline": 41, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BdsVEoGPm1xn3ZITvqI05", + "originalText": "App\nContainer" + }, + { + "type": "rectangle", + "version": 282, + "versionNonce": 2142317191, + "isDeleted": false, + "id": "BAtsinUbrQbPOy_7vN1-C", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1504.2876241405652, + "y": 573.4585561497327, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 119.33613445378151, + "height": 104.5423987776929, + "seed": 1127908521, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "mQiuIgJC5UZh57qLPIScb" + }, + { + "id": "X2pB2_fIS-DSNYmVTfabm", + "type": "arrow" + }, + { + "id": "j3ux1Nne7J7UFkd3jt3nj", + "type": "arrow" + } + ], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 236, + "versionNonce": 1865540969, + "isDeleted": false, + "id": "mQiuIgJC5UZh57qLPIScb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1518.455691367456, + "y": 601.7297555385791, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 91, + "height": 48, + "seed": 1190408393, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 19.70020440608676, + "fontFamily": 1, + "text": "Disruptor\nAgent", + "baseline": 41, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BAtsinUbrQbPOy_7vN1-C", + "originalText": "Disruptor\nAgent" + }, + { + "type": "text", + "version": 131, + "versionNonce": 1096303015, + "isDeleted": false, + "id": "S8pHPOlI5oqJEGX-dXvUv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1018.5, + "y": 546, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 81, + "height": 25, + "seed": 817235849, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "App Pod", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "App Pod" + }, + { + "type": "text", + "version": 101, + "versionNonce": 1350783049, + "isDeleted": false, + "id": "peWk3YjyswXE77R9ZG_qQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1381.5, + "y": 540.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 81, + "height": 25, + "seed": 763244137, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "App Pod", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "App Pod" + }, + { + "type": "arrow", + "version": 456, + "versionNonce": 1486987207, + "isDeleted": false, + "id": "PQ1dAtA3sieLGhmuz-UJ8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 921, + "y": 439.39974019305566, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 280.5348151414312, + "height": 131.26412535316285, + "seed": 1885239625, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124625895, + "link": null, + "locked": false, + "startBinding": { + "elementId": "zaoS3CoqYO9aPd__wHT2s", + "focus": 0.09190364576063259, + "gap": 6 + }, + "endBinding": { + "elementId": "1YeH4cLrEZPr2GYB1IRC7", + "focus": 0.3204512097331312, + "gap": 2.794690603514198 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 244, + 11.600259806944337 + ], + [ + 280.5348151414312, + 131.26412535316285 + ] + ] + }, + { + "type": "arrow", + "version": 916, + "versionNonce": 1981386409, + "isDeleted": false, + "id": "X2pB2_fIS-DSNYmVTfabm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 922.2141848558618, + "y": 438.56615251235826, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 646.8428644661757, + "height": 130.3833748602408, + "seed": 1253206057, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124631575, + "link": null, + "locked": false, + "startBinding": { + "elementId": "zaoS3CoqYO9aPd__wHT2s", + "focus": 0.10895234324530104, + "gap": 7.214184855861845 + }, + "endBinding": { + "elementId": "BAtsinUbrQbPOy_7vN1-C", + "focus": 0.45293430309129595, + "gap": 4.509028777133665 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 567.3703386763672, + 10.383374860240735 + ], + [ + 646.8428644661757, + 130.3833748602408 + ] + ] + }, + { + "type": "arrow", + "version": 913, + "versionNonce": 956850055, + "isDeleted": false, + "id": "j3ux1Nne7J7UFkd3jt3nj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 921.2301204381301, + "y": 837.7028741414802, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 643.1596774520217, + "height": 158, + "seed": 1449491209, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124598131, + "link": null, + "locked": false, + "startBinding": { + "elementId": "schKhW3bFErLrOOzn_n8s", + "focus": 0.19695143573969295, + "gap": 14.730120438130143 + }, + "endBinding": { + "elementId": "BAtsinUbrQbPOy_7vN1-C", + "focus": -0.29002335541045493, + "gap": 1.7019192140544988 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 581.0016051915125, + -15 + ], + [ + 643.1596774520217, + -158 + ] + ] + }, + { + "type": "line", + "version": 237, + "versionNonce": 1988137481, + "isDeleted": false, + "id": "eoWHqLX1_UEMOJiJ_7YQd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 710, + "y": 489, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 55, + "height": 351, + "seed": 1676882409, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 304.8636363636364 + ], + [ + 55, + 351 + ] + ] + }, + { + "type": "text", + "version": 150, + "versionNonce": 487599879, + "isDeleted": false, + "id": "-FDAPC5iGv2ysypL9Q7hD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 583, + "y": 357, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 116, + "height": 25, + "seed": 55833479, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Test script", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Test script" + }, + { + "type": "text", + "version": 284, + "versionNonce": 512977129, + "isDeleted": false, + "id": "zaoS3CoqYO9aPd__wHT2s", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 845, + "y": 410, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70, + "height": 50, + "seed": 774491593, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "X2pB2_fIS-DSNYmVTfabm", + "type": "arrow" + }, + { + "id": "PQ1dAtA3sieLGhmuz-UJ8", + "type": "arrow" + } + ], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Attach\nAgent", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Attach\nAgent" + }, + { + "type": "text", + "version": 268, + "versionNonce": 891901895, + "isDeleted": false, + "id": "schKhW3bFErLrOOzn_n8s", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 773.5, + "y": 824.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 133, + "height": 25, + "seed": 1329577193, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "luD1Apyt6U44VibrdCdVH", + "type": "arrow" + }, + { + "id": "j3ux1Nne7J7UFkd3jt3nj", + "type": "arrow" + } + ], + "updated": 1671124590188, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Inject faults", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Inject faults" + }, + { + "type": "text", + "version": 404, + "versionNonce": 803759049, + "isDeleted": false, + "id": "cSi5CUuXKG76zupUcWU4q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1385.5, + "y": 377.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 265, + "height": 35, + "seed": 1387830793, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 1, + "text": "Kubernetes Cluster", + "baseline": 25, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Kubernetes Cluster" + }, + { + "type": "ellipse", + "version": 313, + "versionNonce": 1813469511, + "isDeleted": false, + "id": "F5UYA0LJaTYaOcVn7K7cW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 729, + "y": 250, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32, + "height": 32, + "seed": 939453127, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "line", + "version": 77, + "versionNonce": 110822057, + "isDeleted": false, + "id": "8K9jj9-q0u0Up2IZXzwng", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 781, + "y": 440, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 58, + "height": 1, + "seed": 1980837545, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 58, + -1 + ] + ] + }, + { + "type": "arrow", + "version": 980, + "versionNonce": 1471378055, + "isDeleted": false, + "id": "lXN-SrvugHJjMXL8OWYoZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 717, + "y": 388, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 560, + "height": 100.25821825682995, + "seed": 907057833, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124576439, + "link": null, + "locked": false, + "startBinding": { + "elementId": "cPG1DdLtDIMbUlka1QvCI", + "focus": -0.3245365228815212, + "gap": 2 + }, + "endBinding": { + "elementId": "QzE_BZRnMzKezAJmK-bKg", + "focus": 0.3481267678801643, + "gap": 3.2546287907987903 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 69, + -97.81993381166058 + ], + [ + 494, + -100.25821825682995 + ], + [ + 560, + -45.75462879079879 + ] + ] + }, + { + "type": "rectangle", + "version": 612, + "versionNonce": 1867957641, + "isDeleted": false, + "id": "QzE_BZRnMzKezAJmK-bKg", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 960, + "y": 345.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 707.9999999999999, + "height": 395.99999999999994, + "seed": 687298631, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "lXN-SrvugHJjMXL8OWYoZ", + "type": "arrow" + } + ], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 82, + "versionNonce": 1787360135, + "isDeleted": false, + "id": "DjeZEald-fIXrCCY252_o", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 740.5, + "y": 253, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 7, + "height": 25, + "seed": 253819271, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "1", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "1" + }, + { + "type": "ellipse", + "version": 247, + "versionNonce": 358034537, + "isDeleted": false, + "id": "mqx_gF_L-pIx9GBoIyeY8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 854, + "y": 370, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32, + "height": 32, + "seed": 1146068809, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 57, + "versionNonce": 1884220071, + "isDeleted": false, + "id": "5ThAP5lJKA8C9SvonJJxa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 862, + "y": 375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16, + "height": 25, + "seed": 561223111, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "2", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "2" + }, + { + "type": "ellipse", + "version": 287, + "versionNonce": 812103497, + "isDeleted": false, + "id": "wumjv_4-bqjxpp0jbvz53", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 821, + "y": 781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32, + "height": 32, + "seed": 179516423, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 112, + "versionNonce": 881393095, + "isDeleted": false, + "id": "DaNRT0xkx8IkDhg0lrTEC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 829, + "y": 786, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16, + "height": 25, + "seed": 340734953, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "3", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "3" + }, + { + "type": "text", + "version": 351, + "versionNonce": 1927538217, + "isDeleted": false, + "id": "Jwqk9NdV_vpqre_QS3Ssq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 765.5, + "y": 251, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 119, + "height": 25, + "seed": 2132679975, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671124558471, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Select Pods", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Select Pods" + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-pod-disruptor-works.png b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-pod-disruptor-works.png new file mode 100644 index 0000000000..2bf4bda103 Binary files /dev/null and b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-pod-disruptor-works.png differ diff --git a/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-service-disruptor-works.excalidraw b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-service-disruptor-works.excalidraw new file mode 100644 index 0000000000..c897381967 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-service-disruptor-works.excalidraw @@ -0,0 +1,1142 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "rectangle", + "version": 436, + "versionNonce": 119787913, + "isDeleted": false, + "id": "7xrm1RkODnRkvGU50r3Yk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 458, + "y": 223, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 353.00000000000006, + "height": 286, + "seed": 597835465, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 137, + "versionNonce": 1256368007, + "isDeleted": false, + "id": "cPG1DdLtDIMbUlka1QvCI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 650, + "y": 391, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 131, + "height": 98, + "seed": 1013022121, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "lXN-SrvugHJjMXL8OWYoZ", + "type": "arrow" + }, + { + "id": "CzHRweCbDeH9aWEFQF61m", + "type": "arrow" + } + ], + "updated": 1671125720207, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 221, + "versionNonce": 1201846377, + "isDeleted": false, + "id": "j3cIUZW2yH8Up7_UVIc37", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 666, + "y": 412, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 50, + "seed": 1106962281, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Pod\nDisruptor", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Pod\nDisruptor" + }, + { + "type": "rectangle", + "version": 264, + "versionNonce": 55713447, + "isDeleted": false, + "id": "Fnk162SSlBZFzwGo6HRry", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 932, + "y": 579.4969442322383, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 192.10847975553855, + "height": 95.00611153552332, + "seed": 651956809, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "f29vtMVlX2R48zMWcJ-B8", + "type": "arrow" + }, + { + "id": "aG2uzLnx4LT7ANaG5o4jV", + "type": "arrow" + } + ], + "updated": 1671125720207, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 142, + "versionNonce": 1561151975, + "isDeleted": false, + "id": "S8pHPOlI5oqJEGX-dXvUv", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 970.5542398777693, + "y": 614.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 115, + "height": 25, + "seed": 817235849, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125728394, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Service Pod", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Service Pod" + }, + { + "type": "text", + "version": 151, + "versionNonce": 1761980871, + "isDeleted": false, + "id": "-FDAPC5iGv2ysypL9Q7hD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 481, + "y": 238, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 116, + "height": 25, + "seed": 55833479, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Test script", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Test script" + }, + { + "type": "text", + "version": 405, + "versionNonce": 1488745001, + "isDeleted": false, + "id": "cSi5CUuXKG76zupUcWU4q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1284, + "y": 408.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 150, + "height": 70, + "seed": 1387830793, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false, + "fontSize": 28, + "fontFamily": 1, + "text": "Kubernetes\nCluster", + "baseline": 60, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Kubernetes\nCluster" + }, + { + "type": "ellipse", + "version": 314, + "versionNonce": 1964630247, + "isDeleted": false, + "id": "F5UYA0LJaTYaOcVn7K7cW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 695, + "y": 266.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32, + "height": 32, + "seed": 939453127, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 981, + "versionNonce": 1788757257, + "isDeleted": false, + "id": "lXN-SrvugHJjMXL8OWYoZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 674, + "y": 313.00000000000006, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 480.5817038412142, + "height": 128.0653050208619, + "seed": 907057833, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false, + "startBinding": { + "elementId": "Kl7ow1AgNJ4Rc4U7YjuFh", + "focus": -0.3396452790633192, + "gap": 2.5 + }, + "endBinding": { + "elementId": "DjfVpYqGjd-hjNkU6rThp", + "focus": 0.25473523028259853, + "gap": 1.2515730230369968 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 121, + -1.8199338116605759 + ], + [ + 419, + 12.741781743170066 + ], + [ + 480.5817038412142, + 126.24537120920132 + ] + ] + }, + { + "type": "rectangle", + "version": 613, + "versionNonce": 1226517511, + "isDeleted": false, + "id": "QzE_BZRnMzKezAJmK-bKg", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 900, + "y": 397.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 556.9999999999999, + "height": 316.99999999999994, + "seed": 687298631, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "lXN-SrvugHJjMXL8OWYoZ", + "type": "arrow" + } + ], + "updated": 1671125720207, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 83, + "versionNonce": 1250081769, + "isDeleted": false, + "id": "DjeZEald-fIXrCCY252_o", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 707.5, + "y": 270, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 7, + "height": 25, + "seed": 253819271, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "1", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "1" + }, + { + "type": "text", + "version": 352, + "versionNonce": 554046247, + "isDeleted": false, + "id": "Jwqk9NdV_vpqre_QS3Ssq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 734, + "y": 257, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 62, + "height": 50, + "seed": 2132679975, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125720207, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Select\nPods", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Select\nPods" + }, + { + "type": "rectangle", + "version": 292, + "versionNonce": 2074076967, + "isDeleted": false, + "id": "4BjK017BDNA0pSeCFeXuD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1178.9457601222307, + "y": 579.4969442322383, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 192.10847975553855, + "height": 95.00611153552332, + "seed": 1239502025, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "aG2uzLnx4LT7ANaG5o4jV", + "type": "arrow" + } + ], + "updated": 1671123865504, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 181, + "versionNonce": 1399615655, + "isDeleted": false, + "id": "f2OqIt7SDf3yOjIL3ASnH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1217.5, + "y": 614.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 115, + "height": 25, + "seed": 960331847, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671125736629, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Service Pod", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Service Pod" + }, + { + "type": "rectangle", + "version": 161, + "versionNonce": 837781863, + "isDeleted": false, + "id": "Kl7ow1AgNJ4Rc4U7YjuFh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 540.5, + "y": 282, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 131, + "height": 98, + "seed": 854260519, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "lXN-SrvugHJjMXL8OWYoZ", + "type": "arrow" + }, + { + "id": "CzHRweCbDeH9aWEFQF61m", + "type": "arrow" + } + ], + "updated": 1671123865504, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 244, + "versionNonce": 1303733385, + "isDeleted": false, + "id": "UELvtjnACaHFGxk6R4bbQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 558, + "y": 306, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 50, + "seed": 1279114695, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671123865504, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Service\nDisruptor", + "baseline": 43, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Service\nDisruptor" + }, + { + "type": "rectangle", + "version": 358, + "versionNonce": 1746003913, + "isDeleted": false, + "id": "DjfVpYqGjd-hjNkU6rThp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1053.9457601222307, + "y": 440.4969442322383, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 192.10847975553855, + "height": 95.00611153552332, + "seed": 1771195111, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "lXN-SrvugHJjMXL8OWYoZ", + "type": "arrow" + } + ], + "updated": 1671123942544, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 251, + "versionNonce": 1917494887, + "isDeleted": false, + "id": "altHvfl5st806_HKJQm9N", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1120, + "y": 475.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70, + "height": 25, + "seed": 1740208905, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671123950692, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Service", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Service" + }, + { + "type": "line", + "version": 37, + "versionNonce": 1273871625, + "isDeleted": false, + "id": "asp42AG24iqeLv8DQvF2B", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1144, + "y": 537, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121, + "height": 43, + "seed": 44891975, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123947476, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -121, + 43 + ] + ] + }, + { + "type": "line", + "version": 66, + "versionNonce": 2044950695, + "isDeleted": false, + "id": "W0a2TuYH1mMRuRpr0ldiy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 1141, + "y": 534, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 132, + "height": 43, + "seed": 1044191305, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123956328, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 132, + 43 + ] + ] + }, + { + "type": "arrow", + "version": 151, + "versionNonce": 2036829895, + "isDeleted": false, + "id": "CzHRweCbDeH9aWEFQF61m", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 673, + "y": 358, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 37, + "height": 33, + "seed": 1916003751, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123865504, + "link": null, + "locked": false, + "startBinding": { + "elementId": "Kl7ow1AgNJ4Rc4U7YjuFh", + "focus": 0.2355940846506884, + "gap": 1.5 + }, + "endBinding": { + "elementId": "cPG1DdLtDIMbUlka1QvCI", + "focus": 0.04792649615098087, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 32, + 6 + ], + [ + 37, + 33 + ] + ] + }, + { + "type": "text", + "version": 124, + "versionNonce": 1572005161, + "isDeleted": false, + "id": "NQTtPveSS0SKktY0MtFpx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 699.5, + "y": 330.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16, + "height": 25, + "seed": 72023721, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671123865504, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "2", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "2" + }, + { + "type": "text", + "version": 398, + "versionNonce": 926424551, + "isDeleted": false, + "id": "ypznEhRL1d7cVpvyYxIzK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 731.5, + "y": 330.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70, + "height": 25, + "seed": 2028493927, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671123865504, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Create", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Create" + }, + { + "type": "ellipse", + "version": 338, + "versionNonce": 240015369, + "isDeleted": false, + "id": "qO3XQVC6N4XAmkdPR-BrM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 693, + "y": 327, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32, + "height": 32, + "seed": 1323304009, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123865504, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 628, + "versionNonce": 356879751, + "isDeleted": false, + "id": "MhTaFrDBWPniMWlfJI1o7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 792, + "y": 745.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 136, + "height": 25, + "seed": 295744809, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "aG2uzLnx4LT7ANaG5o4jV", + "type": "arrow" + }, + { + "id": "f29vtMVlX2R48zMWcJ-B8", + "type": "arrow" + } + ], + "updated": 1671123865505, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Attach agent", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Attach agent" + }, + { + "type": "arrow", + "version": 193, + "versionNonce": 1837612839, + "isDeleted": false, + "id": "f29vtMVlX2R48zMWcJ-B8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 936, + "y": 756, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105, + "height": 79, + "seed": 519202697, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671124462141, + "link": null, + "locked": false, + "startBinding": { + "elementId": "MhTaFrDBWPniMWlfJI1o7", + "focus": 0.228973456987528, + "gap": 8 + }, + "endBinding": { + "elementId": "Fnk162SSlBZFzwGo6HRry", + "focus": -0.23576169018520785, + "gap": 2.49694423223832 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 87, + -7 + ], + [ + 105, + -79 + ] + ] + }, + { + "type": "line", + "version": 127, + "versionNonce": 272501959, + "isDeleted": false, + "id": "1eK3eO1EiNykCmNf_IdJf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 712, + "y": 491, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 82, + "height": 265, + "seed": 1594005063, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123911829, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 4, + 231 + ], + [ + 82, + 265 + ] + ] + }, + { + "type": "arrow", + "version": 309, + "versionNonce": 1547224839, + "isDeleted": false, + "id": "aG2uzLnx4LT7ANaG5o4jV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 932.1046704542987, + "y": 755.9868272741137, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 345, + "height": 74.7368272741137, + "seed": 765379175, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123919054, + "link": null, + "locked": false, + "startBinding": { + "elementId": "MhTaFrDBWPniMWlfJI1o7", + "focus": -0.10366809559389772, + "gap": 4.1046704542986845 + }, + "endBinding": { + "elementId": "4BjK017BDNA0pSeCFeXuD", + "focus": -0.27730938259671256, + "gap": 6.74694423223832 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 302, + -2.7368272741136934 + ], + [ + 345, + -74.7368272741137 + ] + ] + }, + { + "type": "text", + "version": 272, + "versionNonce": 1020097255, + "isDeleted": false, + "id": "QZstzJMHfWUPeE4ZeoQBL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 853.5, + "y": 713.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16, + "height": 25, + "seed": 2042828551, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1671123901263, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "3", + "baseline": 18, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "3" + }, + { + "type": "ellipse", + "version": 458, + "versionNonce": 1462031113, + "isDeleted": false, + "id": "YbtdQlJkgkLQjc-LV3VYt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "x": 845, + "y": 710, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 32, + "height": 32, + "seed": 1222836457, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1671123901263, + "link": null, + "locked": false + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-service-disruptor-works.png b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-service-disruptor-works.png new file mode 100644 index 0000000000..486b19737f Binary files /dev/null and b/src/data/markdown/docs/40 xk6-disruptor/02 Explanations/images/how-service-disruptor-works.png differ diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API.md b/src/data/markdown/docs/40 xk6-disruptor/03 API.md new file mode 100644 index 0000000000..45919ba74d --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API.md @@ -0,0 +1,12 @@ +--- +title: 'API' +excerpt: 'An overview of the API for xk6-disruptor.' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/ +--- + +The xk6-disruptor API is organized around _disruptors_ that affect specific targets such as pods or services. These disruptors can inject different types of [faults](/javascript-api/xk6-disruptor/api/faults) on their targets. + +| Class | Description | +| ----- | ----------- | +| [PodDisruptor](/javascript-api/xk6-disruptor/api/poddisruptor) | Targets the Pods that match selection attributes such as labels.| +| [ServiceDisruptor](/javascript-api/xk6-disruptor/api/servicedisruptor) | Targets the Pods that back a Kubernetes Service | \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults.md new file mode 100644 index 0000000000..3a5b7a55ee --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults.md @@ -0,0 +1,13 @@ +--- +title: 'Faults' +excerpt: 'xk6-disruptor: Fault Description' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/faults/ +--- + +A fault is as an abnormal condition that affects a system component and which may lead to a failure. + +| Fault type | Description | +| ---------- | ---------- | +| [gRPC Fault](/javascript-api/xk6-disruptor/api/faults/grpc) | Fault affecting gRPC requests from a target | +| [HTTP Fault](/javascript-api/xk6-disruptor/api/faults/http) | Fault affecting HTTP requests from a target | +| [Pod Termination Fault](/javascript-api/xk6-disruptor/api/faults/pod-termination) | Fault terminating a number of target Pods | diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/01 Grpc.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/01 Grpc.md new file mode 100644 index 0000000000..89f0128db5 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/01 Grpc.md @@ -0,0 +1,37 @@ +--- +title: 'gRPC' +excerpt: 'xk6-disruptor: gRPC Fault attributes' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/faults/grpc/ +--- + +A gRPC Fault describes the characteristics of the faults to be injected in the gRPC requests served by a target. + +A gRPC fault is described by the following attributes: + +| Attribute | Type | Description | +| -------------- | ------ | -------| +| averageDelay | string | average delay added to requests represented as a string (default `0`) | +| delayVariation | string | variation in the injected delay (default `0`) | +| statusMessage | string | message to be returned when an error is injected | +| statusCode | number | status to be returned when an error is injected | +| errorRate | number | rate of requests that will return an error, represented as a float in the range `0.0` to `1.0` (default `0.0`) | +| exclude | string | comma-separated list of services to be excluded from disruption | +| port | number | port on which the requests will be intercepted | + +
+ +`averageDelay` and `delayVariation` are applied to all requests affected by the fault, regardless of the value of `errorRate`. `statusCode` is returned only to a fraction of requests defined by `errorRate`. + +
+ +## Example + +This example defines a gRPC fault that introduces a delay of `50ms` in all requests and returns a status code `13` in `10%` of the requests. + +```javascript +const fault = { + averageDelay: '50ms', + statusCode: 10, + errorRate: 0.1, +}; +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/02 HTTP .md b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/02 HTTP .md new file mode 100644 index 0000000000..8bae1a4dae --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/02 HTTP .md @@ -0,0 +1,37 @@ +--- +title: 'HTTP' +excerpt: 'xk6-disruptor: HTTP Fault attributes' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/faults/http/ +--- + +A HTTP Fault describes the characteristics of the faults to be injected in the HTTP requests served by a target. + +A HTTP fault is described by the following attributes: + +| Attribute | Type | Description | +| ------------- | ------ | --------| +| averageDelay | string | average delay added to requests represented as a string (default `0`) | +| delayVariation| string | variation in the injected delay (default `0`) | +| errorBody | string | body to be returned when an error is injected | +| errorCode | number | error code to return | +| errorRate | number | rate of requests that will return an error, represented as a float in the range `0.0` to `1.0` (default `0.0`) | +| exclude | string | comma-separated list of urls to be excluded from disruption (e.g. /health) | +| port | number | port on which the requests will be intercepted | + +
+ +`averageDelay` and `delayVariation` are applied to all requests affected by the fault, regardless of the value of `errorRate`. `errorCode` is returned only to a fraction of requests defined by `errorRate`. + +
+ +## Example + +This example defines a HTTP fault that introduces a delay of `50ms` in all requests and returns an error code `500` in `10%` of the requests. + +```javascript +const fault = { + averageDelay: '50ms', + errorCde: 500, + errorRate: 0.1, +}; +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/03 Pod Termination.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/03 Pod Termination.md new file mode 100644 index 0000000000..70e05f0aed --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/01 Faults/03 Pod Termination.md @@ -0,0 +1,29 @@ +--- +title: 'Pod Termination' +excerpt: 'xk6-disruptor: Pod Termination Fault attributes' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/faults/pod-termination/ +--- + +A Pod Termination Fault allows terminating either a fixed number or a percentage of the pods that matching a selector or back a service. + +A Pod Termination fault is defined by the following attributes: + +| Attribute | Type | Description | +| ------------- | ------ | --------| +| count | integer or percentage | the number of pods to be terminated. It can be specified as a integer number or as a percentage (e.g. `30%`) that defines the fraction of target pods to be terminated| + + +
+If the count is a percentage and there are no enough elements in the target pod list, the number is rounded up. +For example '25%' of a list of 2 target pods will terminate one pod. +If the list of target pods is not empty, at least one pod is always terminated. +
+ +## Example + +This example defines a PorTermination fault that will terminate `30%` of target pods +```javascript +const fault = { + count: '30%' +}; +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor.md new file mode 100644 index 0000000000..db3a904015 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor.md @@ -0,0 +1,61 @@ +--- +title: 'PodDisruptor' +excerpt: 'xk6-disruptor: PodDisruptor class' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/poddisruptor/ +--- + +The `PodDisruptor` class can inject different types of faults into the pods that match a selection criteria. + +To construct a `PodDisruptor`, use the [PodDisruptor() constructor](/javascript-api/xk6-disruptor/api/poddisruptor/constructor). + +## Methods + +| Method | Description | +| ------ | ----------- | +| [PodDisruptor.injectGrpcFaults()](/javascript-api/xk6-disruptor/api/poddisruptor/injectgrpcfaults) | Inject [gRPC faults](/javascript-api/xk6-disruptor/api/faults/grpc) in the target Pods| +| [PodDisruptor.injectHTTPFaults()](/javascript-api/xk6-disruptor/api/poddisruptor/injecthttpfaults) | Inject [HTTP faults](/javascript-api/xk6-disruptor/api/faults/http) in the target Pods| +| PodDisruptor.targets() | Returns the list of target Pods of the PodDisruptor | +| [PodDisruptor.terminatePods()](/javascript-api/xk6-disruptor/api/poddisruptor/terminatepods) | executes a [Pod Termination fault](/javascript-api/xk6-disruptor/api/faults/pod-termination) in the target Pods| + + +## Example + +This example: +- Creates a selector that matches all pods in the `default` namespace with the `run=nginx` label +- Injects a delay of 100ms and makes 10 percent of requests return an http response code `500`. + + +```javascript +import { PodDisruptor } from 'k6/x/disruptor'; + +const selector = { + namespace: 'default', + select: { + labels: { + run: 'nginx', + }, + }, +}; + +const fault = { + averageDelay: '100ms', + errorRate: 0.1, + errorCode: 500, +}; + +export default function () { + const disruptor = new PodDisruptor(selector); + disruptor.injectHTTPFaults(fault, '30s'); +} +``` + +
+ +You can test this script by first creating a pod running nginx with the command below, assuming you have [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) installed in your environment: +```bash +$ kubectl run nginx --image=nginx +``` + + You can also use the [xk6-kubernetes](https://github.com/grafana/xk6-kubernetes) extension for creating these resources from your test script. + +
\ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/01 Constructor.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/01 Constructor.md new file mode 100644 index 0000000000..abd9d012ea --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/01 Constructor.md @@ -0,0 +1,56 @@ +--- +title: 'Constructor' +excerpt: 'xk6-disruptor: PodDisruptor constructor' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/poddisruptor/constructor/ +--- + + +The `PodDisruptor()` constructor creates a new instance of a [PodDisruptor](/javascript-api/xk6-disruptor/api/poddisruptor) class. + + +| Parameter | Type | Description | +| --------- | -----| ------ | +| selector | object | [criteria](#selector) for selecting the target pods | +| options (optional) | object | [options](#options) for controlling the behavior of the disruptor | + +### Selector + +The `selector` defines the criteria a pod must satisfy to be a valid target: + +| Attribute | Type | Description | +| --------- | -----|------------ | +| namespace | string | namespace the selector will look for pods | +| select | object | [attributes](#pod-attributes) that a pod must match to be selected | +| exclude | object | [attributes](#pod-attributes) that exclude a pod (even if it matches the select attributes) | + +You can use the following attributes to select or exclude pods: + +### Pod attributes + +| Attribute | Type | Description | +| --------- | -------| ----------- | +| labels | object | map with the labels to be matched for selection or exclusion | + +### Options + +The `options` control the creation and behavior of the `PodDisruptor`: + +| Attribute | Type | Description | +| --------- | -----|------ | +| injectTimeout | string | maximum time to wait for the disruptor to be ready in the target pods (default 30s) | + +## Example + + + +```javascript + const selector = { + namespace: "my-namespace", + select: { + labels: { + app: "my-app" + } + } + } + const podDisruptor = new PodDisruptor(selector) +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/02 injectGrpcFaults.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/02 injectGrpcFaults.md new file mode 100644 index 0000000000..7f29dc3e34 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/02 injectGrpcFaults.md @@ -0,0 +1,36 @@ +--- +title: 'injectGrpcFaults()' +excerpt: 'xk6-disruptor: PodDisruptor.injectGrpcFaults method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/poddisruptor/injectgrpcfaults/ +--- + +injectGrpcFaults injects gRPC faults in the requests served by a target Pod. + +| Parameter | Type | Description | +| --------- | ------ |------- | +| fault | object | description of the [gRPC faults](/javascript-api/xk6-disruptor/api/faults/grpc) to be injected | +| duration | string | duration of the disruption | +| options (optional) | object | [options](#options) that control the injection of the fault | + + +## options + +The injection of the fault is controlled by the following options: + +| Option | Type | Description | +| --------- | ------ | -------- | +| proxyPort | number | port the agent will use to listen for requests in the target pods ( default `8000`) | + + +## Example + + + +```javascript + const fault = { + averageDelay: "50ms", + statusCode: 13, + errorRate: 0.1 + } + disruptor.injectGrpcFaults(fault, "30s") +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/03 injectHTTPFaults.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/03 injectHTTPFaults.md new file mode 100644 index 0000000000..748f81579b --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/03 injectHTTPFaults.md @@ -0,0 +1,45 @@ +--- +title: 'injectHTTPFaults()' +excerpt: 'xk6-disruptor: PodDisruptor.injectHTTPFaults method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/poddisruptor/injecthttpfaults/ +--- + +injectHTTPFaults injects HTTP faults in the requests served by a target Pod. + +| Parameter | Type | Description | +| --------- | ------ | ------- | +| fault | object | description of the [http faults](/javascript-api/xk6-disruptor/api/faults/http) to be injected | +| duration | string | duration of the disruption | +| options (optional) | object | [options](#options) that control the injection of the fault | + + +## options + +The injection of the fault is controlled by the following options: + +| Option | Type | Description | +| --------- | ------ | -------- | +| proxyPort | number | port the agent will use to listen for requests in the target pods ( default `8000`) | + +
+ +When injecting faults you may find the following error message during the test execution: + +WARN\[0035\] Request Failed error="read tcp 172.18.0.1:43564->172.18.255.200:80: read: connection reset by peer" + +This is normal and means that one request was "in transit" at the time the faults were injected, causing the request to fail from a network connection reset. + +
+ +## Example + + + +```javascript + const fault = { + averageDelay: "50ms", + errorCode: 500, + errorRate: 0.1 + } + disruptor.injectHTTPFaults(fault, "30s") +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/04 TerminatePods.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/04 TerminatePods.md new file mode 100644 index 0000000000..51e9bf0946 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/02 PodDisruptor/04 TerminatePods.md @@ -0,0 +1,23 @@ +--- +title: 'terminatePods()' +excerpt: 'xk6-disruptor: PodDisruptor.terminatePods method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/poddisruptor/terminate-pods/ +--- + +`terminatePods` terminates a number of the pods matching the selector configured in the PodDisruptor. + +| Parameter | Type | Description | +| --------- | ------ |------- | +| fault | object | description of the [Pod Termination fault](/javascript-api/xk6-disruptor/api/faults/pod-termination) | + + +## Example + + + +```javascript + const fault = { + count: 2, + } + disruptor.terminatePods(fault) +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor.md new file mode 100644 index 0000000000..b6c9d7d21f --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor.md @@ -0,0 +1,55 @@ +--- +title: 'ServiceDisruptor' +excerpt: 'xk6-disruptor: ServiceDisruptor class' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/servicedisruptor/ +--- + +The `ServiceDisruptor` class can inject different types of faults into the pods that back a Kubernetes service. + +To construct a `ServiceDisruptor`, use the [ServiceDisruptor() constructor](/javascript-api/xk6-disruptor/api/servicedisruptor/constructor). + + +## Methods + +| Method | Description | +| ------ | ----------- | +| [ServiceDisruptor.injectGrpcFaults()](/javascript-api/xk6-disruptor/api/servicedisruptor/injectgrpcfaults) | Inject [gRPC faults](/javascript-api/xk6-disruptor/api/faults/grpc) in the target Pods| +| [ServiceDisruptor.injectHTTPFaults()](/javascript-api/xk6-disruptor/api/servicedisruptor/injecthttpfaults) | Inject [HTTTP faults](/javascript-api/xk6-disruptor/api/faults/http) in the target Pods| +| ServiceDisruptor.targets() | Returns the list of target Pods of the ServiceDisruptor | +| [ServiceDisruptor.terminatePods()](/javascript-api/xk6-disruptor/api/servicedisruptor/terminatepods) | executes a [Pod Termination fault](/javascript-api/xk6-disruptor/api/faults/pod-termination) in the target Pods| + + +## Example + +The following example: +- Creates a disruptor for the `nginx` service +- Injects a delay of 100ms and a 10 percent of requests that return an http response code `500`. + +```javascript +import { ServiceDisruptor } from 'k6/x/disruptor'; + +const fault = { + averageDelay: '100ms', + errorRate: 0.1, + errorCode: 500, +}; + +export default function () { + const disruptor = new ServiceDisruptor('nginx', 'default'); + disruptor.injectHTTPFaults(fault, '30s'); +} +``` + +
+ +You can test this script by creating first a pod running nginx and exposing it as a service with the commands below, assuming you have [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) installed in your environment: + +```bash +> kubectl run nginx --image=nginx +> kubectl expose pod nginx --port 80 +``` + +You can also use the [xk6-kubernetes](https://github.com/grafana/xk6-kubernetes) extension for creating these resources from your test script. + +
+ diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/01 Constructor.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/01 Constructor.md new file mode 100644 index 0000000000..98b4f60cd3 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/01 Constructor.md @@ -0,0 +1,32 @@ +--- +title: 'Constructor' +excerpt: 'xk6-disruptor: ServiceDisruptor constructor' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/servicedisruptor/constructor/ +--- + + +The `ServiceDisruptor()` constructor creates a new instance of a [ServiceDisruptor](/javascript-api/xk6-disruptor/api/servicedisruptor) class. + + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| service | string | name of the service | +| namespace | string | namespace on which the service is defined | +| options (optional) | object | [options](#options) for controlling the behavior of the disruptor | + + +### Options + +The following options control the creation and behavior of the `ServiceDisruptor`: + +| Attribute | Type | Description | +| --------- | ---- |------ | +| injectTimeout | string | maximum time for waiting the disruptor to be ready in the target pods (default 30s) | + +## Example + + + +```javascript + const disruptor = new ServiceDisruptor('my-service', 'my-namespace'); +``` diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/02 injectGrpcFaults.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/02 injectGrpcFaults.md new file mode 100644 index 0000000000..f7075938c8 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/02 injectGrpcFaults.md @@ -0,0 +1,34 @@ +--- +title: 'injectGrpcFaults' +excerpt: 'xk6-disruptor: ServiceDisruptor.injectGrpcFaults method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/servicedisruptor/injectgrpcfaults/ +--- + +injectGrpcFaults injects gRPC faults in the requests served by a target Service. + +| Parameters | Type | Description | +| ---------- | ------ | ------- | +| fault | object | description of the [gRPC faults](/javascript-api/xk6-disruptor/api/faults/grpc) to be injected | +| duration | string | duration of the disruption | +| options (optional) | object | [options](#options) that control the injection of the fault | + +## Options + +The injection of the fault is controlled by the following options: + +| Option | Type | Description | +| --------- | ------ | ------- | +| proxyPort | number | port the agent will use to listen for requests in the target pods ( default `8000`) | + +## Example + + + +```javascript + const fault = { + averageDelay: "50ms", + statusCode: 13, + errorRate: 0.1 + } + disruptor.injectGrpcFaults(fault, "30s") +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/03 injectHTTPFaults.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/03 injectHTTPFaults.md new file mode 100644 index 0000000000..6d47adf740 --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/03 injectHTTPFaults.md @@ -0,0 +1,44 @@ +--- +title: 'injectHTTPFaults' +excerpt: 'xk6-disruptor: ServiceDisruptor.injectHTTPFaults method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/servicedisruptor/injecthttpfaults/ +--- + +injectHTTPFaults injects HTTP faults in the requests served by a target Service. + +| Parameters | Type | Description | +| ---------- | ------ | ----------- | +| fault | object | description of the [http faults](/javascript-api/xk6-disruptor/api/faults/http) to be injected | +| duration | string | duration of the disruption | +| options (optional) | object | [options](#options) that control the injection of the fault | + +## Options + +The injection of the fault is controlled by the following options: + +| Option | Type | Description | +| --------- | ------ | ----------- | +| proxyPort | number | port the agent will use to listen for requests in the target pods ( default `8000`) | + +
+ +When injecting faults you may find the following error message during the test execution: + +WARN\[0035\] Request Failed error="read tcp 172.18.0.1:43564->172.18.255.200:80: read: connection reset by peer". + +This is normal and means that one request was "in transit" at the time the faults were injected causing the request to fail due to a network connection reset. + +
+ +## Example + + + +```javascript + const fault = { + averageDelay: "50ms", + errorCode: 500, + errorRate: 0.1 + } + disruptor.injectHTTPFaults(fault, "30s") +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/04 TerminatePods.md b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/04 TerminatePods.md new file mode 100644 index 0000000000..ccd0af30bf --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/03 API/03 ServiceDisruptor/04 TerminatePods.md @@ -0,0 +1,23 @@ +--- +title: 'terminatePods()' +excerpt: 'xk6-disruptor: ServiceDisruptor.terminatePods method' +canonicalUrl: https://grafana.com/docs/k6/latest/javascript-api/xk6-disruptor/servicedisruptor/terminate-pods/ +--- + +`terminatePods` terminates a number of pods that belong to the service specified in the ServiceDisruptor. + +| Parameter | Type | Description | +| --------- | ------ |------- | +| fault | object | description of the [Pod Termination fault](/javascript-api/xk6-disruptor/api/faults/pod-termination) | + + +## Example + + + +```javascript + const fault = { + count: 2, + } + disruptor.terminatePods(fault) +``` \ No newline at end of file diff --git a/src/data/markdown/docs/40 xk6-disruptor/04 Examples.md b/src/data/markdown/docs/40 xk6-disruptor/04 Examples.md new file mode 100644 index 0000000000..5cb4596cca --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/04 Examples.md @@ -0,0 +1,16 @@ +--- +title: 'Examples' +excerpt: 'Examples of how to use the xk6-disruptor extension to introduce faults in k6 tests.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/examples/ +--- + +In this section, we present some examples of using the `xk6-disruptor` extension to introduce faults in `k6` tests. + +- [Injecting gRPC faults into a Service](/javascript-api/xk6-disruptor/examples/inject-grpc-faults-into-service) +- [Injecting HTTP faults into a Pod](/javascript-api/xk6-disruptor/examples/inject-http-faults-into-pod) +- [Interactive demo](https://killercoda.com/grafana-xk6-disruptor/scenario/killercoda) (Killercoda) + +To follow the instructions of the examples, check first the system under test meets the [requirements](/javascript-api/xk6-disruptor/get-started/requirements/) to receive faults, in particular: +- You have configured the credentials to access the Kubernetes cluster. +- This cluster exposes the service using an external IP. + diff --git a/src/data/markdown/docs/40 xk6-disruptor/04 Examples/01 Inject Grpc faults into Service.md b/src/data/markdown/docs/40 xk6-disruptor/04 Examples/01 Inject Grpc faults into Service.md new file mode 100644 index 0000000000..5955dc649e --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/04 Examples/01 Inject Grpc faults into Service.md @@ -0,0 +1,444 @@ +--- +title: 'Inject gRPC faults into Service' +excerpt: 'This example shows how to test the effect of faults injected in the gRPC requests served by a service.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/examples/inject-grpc-faults-into-service/ +--- + +This example shows a way to use the [ServiceDisruptor](/javascript-api/xk6-disruptor/api/servicedisruptor) to test the effect of faults injected in the gRPC requests served by a service. + +The complete [source code](#source-code) is at the end of this document. The next sections examine the code in detail. + +The example uses [grpcpbin](https://grpcbin.test.k6.io), a simple request/response application that offers endpoints for testing different gRPC requests. + +The test requires `grpcpbin` to be deployed in a cluster in the namespace `grpcbin` and exposed with an external IP. The IP address is expected in the environment variable `GRPC_HOST`. + +For the Kubernetes manifests and the instructions on how to deploy it to a cluster, refer to the [test setup](#test-setup) section at the end of this document. To learn more about how to get the external IP address, refer to [Expose your application](/javascript-api/xk6-disruptor/get-started/expose-your-application). + + +## Initialization + +The initialization code imports the external dependencies required by the test. The [ServiceDisruptor](https://k6.io/docs/javascript-api/xk6-disruptor/api/servicedisruptor/) class imported from the `xk6-disruptor` extension provides functions for injecting faults in services. The [k6/net/grpc](https://k6.io/docs/javascript-api/k6-net-grpc/) module provides functions for executing gRPC requests. The [check](https://k6.io/docs/javascript-api/k6/check/) function verifies the results from the requests. + + +```javascript +import { ServiceDisruptor } from 'k6/x/disruptor'; +import grpc from 'k6/net/grpc'; +import { check } from 'k6'; + ``` + +We also create a grpc client and load the protobufs definitions for the [HelloService](https://github.com/moul/pb/blob/master/hello/hello.proto) service. + + +```javascript +const client = new grpc.Client(); +client.load(['pb'], 'hello.proto'); +``` + +## Test Load + +The test load is generated by the `default` function, which connects to the `grpcbin` service using the IP and port obtained from the environment variable `GRPC_HOST` and invokes the `SayHello` method of the `hello.HelloService` service. Finally, The status code of the response is checked. When faults are injected, this check should fail. + +```javascript +export default function () { + client.connect( + __ENV.GRPC_HOST, + { + plaintext: true, + timeout: '1s' + } + ); + + const data = { greeting: 'Bert' }; + const response = client.invoke( + 'hello.HelloService/SayHello', + data, + { + timeout: '1s' + } + ); + client.close() + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + +} + ``` + +## Fault injection + +The `disrupt` function creates a `ServiceDisruptor` for the `grpcbin` service in the namespace `grpcbin`. + +The gRPC faults are injected by calling the [ServiceDisruptor.injectGrpcFaults](/javascript-api/xk6-disruptor/api/servicedisruptor/injectgrpcfaults) method using a fault definition that introduces a delay of `300ms` on each request and an error with status code `13` ("Internal error") in `10%` of the requests. + + +```javascript +export function disrupt() { + if (__ENV.SKIP_FAULTS == "1") { + return + } + + const fault = { + averageDelay: "300ms", + statusCode: grpc.StatusInternal, + errorRate: 0.1, + port: 9000, + } + const disruptor = new ServiceDisruptor('grpcbin','grpcbin') + disruptor.injectGrpcFaults(fault, "30s") +} +``` + +Notice the following code snippet in the `injectFaults` function above: + +```javascript + if (__ENV.SKIP_FAULTS == "1") { + return + } +``` + +This code makes the function return without injecting faults if the `SKIP_FAULTS` environment variable is passed to the execution of the test with a value of "1". We will use this option to obtain a [baseline execution](#baseline-execution) without faults. + +## Scenarios + +This test defines two [scenarios](https://k6.io/docs/using-k6/scenarios) to be executed. The `load` scenario applies the test load to the `grpcpbin` application for `30s` invoking the `default` function. The `disrupt` scenario invokes the `disrupt` function to inject a fault in the gRPC requests to the target application. + +```javascript + scenarios: { + load: { + executor: 'constant-arrival-rate', + rate: 100, + preAllocatedVUs: 10, + maxVUs: 100, + exec: "default", + startTime: '0s', + duration: "30s", + }, + disrupt: { + executor: 'shared-iterations', + iterations: 1, + vus: 1, + exec: "disrupt", + startTime: "0s", + } + } + ``` + +
+ + The `disrupt` scenario uses a `shared-iterations` executor with one iteration and one `VU`. This setting ensures the `disrupt` function is executed only once. Executing this function multiples times concurrently may have unpredictable results. + +
+ + +## Executions + +
+ +The commands in this section assume the `xk6-disruptor` binary is available in your current directory. This location can change depending on the installation process and the platform. Refer to [Installation](/javascript-api/xk6-disruptor/get-started/installation) for details on how to install it in your environment. + +
+ +### Baseline execution + +We will first execute the test without introducing faults to have an baseline using the following command: + + + +```bash +xk6-disruptor --env SKIP_FAULTS=1 --env GRPC_HOST=$GRPC_HOST run grpc-faults.js +``` + +```PowerShell +xk6-disruptor --env SKIP_FAULTS=1 --env "GRPC_HOST=$Env:GRPC_HOST" run grpc-faults.js +``` + + + +Notice the argument `--env SKIP_FAULT=1`, which makes the `disrupt` function return without injecting any fault as explained in the [fault injection](#fault-injection) section. Also notice the `--env GRPC_HOST` argument, which passes the external IP used to access the `grpcbin` application. + +You should get an output similar to the following (use the `Expand` button to see all output). + + + +``` + /\ |‾‾| /‾‾/ /‾‾/ + /\ / \ | |/ / / / + / \/ \ | ( / ‾‾\ + / \ | |\ \ | (‾) | + / __________ \ |__| \__\ \_____/ .io + + execution: local + script: scripts/grpc-faults.js + output: - + + scenarios: (100.00%) 2 scenarios, 101 max VUs, 10m30s max duration (incl. graceful stop): + * disrupt: 1 iterations shared among 1 VUs (maxDuration: 10m0s, exec: disrupt, gracefulStop: 30s) + * load: 100.00 iterations/s for 30s (maxVUs: 10-100, exec: default, gracefulStop: 30s) + + +running (00m30.0s), 000/011 VUs, 3001 complete and 0 interrupted iterations +disrupt ✓ [======================================] 1 VUs 00m00.0s/10m0s 1/1 shared iters +load ✓ [======================================] 000/010 VUs 30s 100.00 iters/s + + ✓ status is OK + + checks...............: 100.00% ✓ 3000 ✗ 0 + data_received........: 416 kB 14 kB/s + data_sent............: 630 kB 21 kB/s + grpc_req_duration....: avg=1.36ms min=512.43µs med=1.25ms max=26.62ms p(90)=1.75ms p(95)=2.09ms + iteration_duration...: avg=4.4ms min=52.86µs med=4.01ms max=66.26ms p(90)=5.32ms p(95)=6.35ms + iterations...........: 3001 100.028406/s + vus..................: 10 min=10 max=10 + vus_max..............: 11 min=11 max=11 +``` + + + +### Fault injection + +We repeat the execution injecting the faults. Notice we have removed the `--env SKIP_FAULTS=1` argument. + + + +```bash +xk6-disruptor --env GRPC_HOST=$GRPC_HOST run grpc-faults.js +``` + +```PowerShell +xk6-disruptor --env "GRPC_HOST=$Env:GRPC_HOST" run grpc-faults.js +``` + + + + + +``` + /\ |‾‾| /‾‾/ /‾‾/ + /\ / \ | |/ / / / + / \/ \ | ( / ‾‾\ + / \ | |\ \ | (‾) | + / __________ \ |__| \__\ \_____/ .io + + execution: local + script: scripts/grpc-faults.js + output: - + + scenarios: (100.00%) 2 scenarios, 101 max VUs, 10m30s max duration (incl. graceful stop): + * disrupt: 1 iterations shared among 1 VUs (maxDuration: 10m0s, exec: disrupt, gracefulStop: 30s) + * load: 100.00 iterations/s for 30s (maxVUs: 10-100, exec: default, gracefulStop: 30s) + + +running (00m50.6s), 000/033 VUs, 2975 complete and 0 interrupted iterations +disrupt ✓ [======================================] 1 VUs 00m50.6s/10m0s 1/1 shared iters +load ✓ [======================================] 000/032 VUs 30s 100.00 iters/s + + ✗ status is OK + ↳ 89% — ✓ 2668 / ✗ 306 + + checks...............: 89.71% ✓ 2668 ✗ 306 + data_received........: 405 kB 8.0 kB/s + data_sent............: 615 kB 12 kB/s + dropped_iterations...: 26 0.513628/s + grpc_req_duration....: avg=270.51ms min=502.12µs med=302.34ms max=310.48ms p(90)=303.25ms p(95)=303.57ms + iteration_duration...: avg=290.05ms min=1.96ms med=304.86ms max=50.61s p(90)=306.36ms p(95)=306.89ms + iterations...........: 2975 58.770842/s + vus..................: 1 min=1 max=33 + vus_max..............: 33 min=25 max=33 +``` + + +### Comparison + +Let's take a closer look at the results for the requests on each scenario. We can observe that in the `base` scenario requests duration has an percentile 95 of `2.09ms` and `100%` of requests pass the check. The `faults` scenario has a percentile 96 of `303.57ms` and only `89%` of requests pass the check (or put in another way, `11%` of requests failed), closely matching the fault definition. + +| Execution | P95 Req. Duration | Passed Checks | +| --------------- | ----------------- | -------------- | +| Baseline | 2.09ms | 100% | +| Fault injection | 303.57ms | 89% | + + +## Source Code + + + +```javascript +import { ServiceDisruptor } from 'k6/x/disruptor'; +import grpc from 'k6/net/grpc'; +import { check } from 'k6'; + +const client = new grpc.Client(); +client.load(['pb'], 'hello.proto'); + +export default function () { + client.connect( + __ENV.GRPC_HOST, + { + plaintext: true, + timeout: '1s' + } + ); + + const data = { greeting: 'Bert' }; + const response = client.invoke( + 'hello.HelloService/SayHello', + data, + { + timeout: '1s' + } + ); + client.close() + + check(response, { + 'status is OK': (r) => r && r.status === grpc.StatusOK, + }); + +} + +export function disrupt() { + if (__ENV.SKIP_FAULTS == "1") { + return + } + + const disruptor = new ServiceDisruptor('grpcbin','grpcbin') + + // inject errors in requests + const fault = { + averageDelay: "300ms", + statusCode: grpc.StatusInternal, + errorRate: 0.1, + port: 9000, + } + disruptor.injectGrpcFaults(fault, "30s") +} + +export const options = { + scenarios: { + load: { + executor: 'constant-arrival-rate', + rate: 100, + preAllocatedVUs: 10, + maxVUs: 100, + exec: "default", + startTime: '0s', + duration: "30s", + }, + disrupt: { + executor: 'shared-iterations', + iterations: 1, + vus: 1, + exec: "disrupt", + startTime: "0s", + } + } +} +``` + + + + + +``` +syntax = "proto2"; + +package hello; + +service HelloService { + rpc SayHello(HelloRequest) returns (HelloResponse); + rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse); + rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse); + rpc BidiHello(stream HelloRequest) returns (stream HelloResponse); +} + +message HelloRequest { + optional string greeting = 1; +} + +message HelloResponse { + required string reply = 1; +} +``` + + + +## Test setup + +The tests requires the deployment of the `grpcbin` application. The application must also be accessible using an external IP available in the `GRPC_HOST` environment variable. + +The following [manifests](#manifests) define the resources required for deploying the application and exposing it as a LoadBalancer service. + +You can deploy the application using the following commands: + +```bash +# Create Namespace +kubectl apply -f namespace.yaml +namespace/grpcbin created + +# Deploy Pod +kubectl apply -f pod.yaml +pod/grpcbin created + +# Expose Pod as a Service +kubectl apply -f service.yaml +service/grpcbin created +``` + +You must set the environment variable `GRPC_HOST` with the external IP address and port used to access the `grpcbin` service from the test script. + +Learn more about how to get the external IP address in the [Expose your application](/javascript-api/xk6-disruptor/get-started/expose-your-application). + +### Manifests + + + +```yaml +apiVersion: "v1" +kind: Namespace +metadata: + name: grpcbin +``` + + + + + +```yaml +kind: "Pod" +apiVersion: "v1" +metadata: + name: grpcbin + namespace: grpcbin + labels: + app: grpcbin +spec: + containers: + - name: grpcbin + image: moul/grpcbin + ports: + - name: http + containerPort: 9000 + +``` + + + + + + +```yaml +apiVersion: "v1" +kind: "Service" +metadata: + name: grpcbin + namespace: grpcbin +spec: + selector: + app: grpcbin + type: "NodePort" + ports: + - port: 9000 + targetPort: 9000 +``` + + + diff --git a/src/data/markdown/docs/40 xk6-disruptor/04 Examples/02 Inject HTTP faults into Pod.md b/src/data/markdown/docs/40 xk6-disruptor/04 Examples/02 Inject HTTP faults into Pod.md new file mode 100644 index 0000000000..5ce94d38cd --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/04 Examples/02 Inject HTTP faults into Pod.md @@ -0,0 +1,417 @@ +--- +title: 'Inject HTTP faults into Pod' +excerpt: 'This example shows how to test the effect of faults injected in the HTTP requests served by a pod.' +canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/injecting-faults-with-xk6-disruptor/examples/inject-http-faults-into-pod/ +--- + +This example shows how [PodDisruptor](/javascript-api/xk6-disruptor/api/poddisruptor) can be used for testing the effect of faults injected in the HTTP requests served by a pod. + +You will find the complete [source code](#source-code) at the end of this document. Next sections examine the code in detail. + +The example uses [httpbin](https://httpbin.org), a simple request/response application that offers endpoints for testing different HTTP requests. + +The test requires `httpbin` to be deployed in a cluster in the namespace `httpbin` and exposed with an external IP. the IP address is expected in the environment variable `SVC_IP`. + +You will find the Kubernetes manifests and the instructions of how to deploy it to a cluster in the [test setup](#test-setup) section at the end of this document. You can learn more about how to get the external IP address in the [expose your application](/javascript-api/xk6-disruptor/get-started/expose-your-application) section. + + +## Initialization + +The initialization code imports the external dependencies required by the test. The `PodDisruptor` class imported from the `xk6-disruptor` extension provides functions for injecting faults in pods. The [k6/http](https://k6.io/docs/javascript-api/k6-http/) module provides functions for executing HTTP requests. + + +```javascript +import { PodDisruptor } from 'k6/x/disruptor'; +import http from 'k6/http'; + ``` + +## Test Load + +The test load is generated by the `default` function, which executes a request to the `httpbin` pod using the IP obtained from the environment variable `SVC_IP`. The test makes requests to the endpoint `delay/0.1` which will return after `0.1` seconds (`100ms`). + +```javascript +export default function(data) { + http.get(`http://${data.SVC_IP}/delay/0.1`); +} + ``` + +
+ + The test uses the `delay` endpoint which return after the requested delay. It requests a `0.1s` (`100ms`) delay to ensure the baseline scenario (see scenarios below) has meaningful statistics for the request duration. If we were simply calling a locally deployed http server (for example `nginx`), the response time would exhibit a large variation between a few microseconds to a few milliseconds. Having `100ms` as baseline response time has proved to offer more consistent results. + +
+ +## Fault injection + +The `disrupt` function creates a `PodDisruptor` using a selector that matches pods in the namespace `httpbin` with the label `app: httpbin`. + +The http faults are injected by calling the [PodDisruptor.injectHTTPFaults](/javascript-api/xk6-disruptor/api/poddisruptor/injecthttpfaults) method using a fault definition that introduces a delay of `50ms` on each request and an error code `500` in `10%` of the requests. + + +```javascript +export function disrupt(data) { + if (__ENV.SKIP_FAULTS == "1") { + return + } + const selector = { + namespace: namespace, + select: { + labels: { + app: "httpbin" + } + } + } + const podDisruptor = new PodDisruptor(selector) + // delay traffic from one random replica of the deployment + const fault = { + averageDelay: "50ms", + errorCode: 500, + errorRate: 0.1 + } + podDisruptor.injectHTTPFaults(fault, "30s") +} +``` + +Notice the following code snippet in the `injectFaults` function above: + +```javascript + if (__ENV.SKIP_FAULTS == "1") { + return + } +``` + +This code makes the function return without injecting faults if the `SKIP_FAULTS` environment variable is passed to the execution of the test with a value of "1". We will use this option to obtain a [baseline execution](#baseline-execution) without faults. + +## Scenarios + +This test defines two [scenarios](https://k6.io/docs/using-k6/scenarios) to be executed. The `load` scenario applies the test load to the `httpbin` application for `30s` invoking the `default` function. The `disrupt` scenario invokes the `disrupt` function to inject a fault in the HTTP requests of the target application. + +```javascript + scenarios: { + load: { + executor: 'constant-arrival-rate', + rate: 100, + preAllocatedVUs: 10, + maxVUs: 100, + exec: "default", + startTime: "0s", + duration: "30s", + }, + disrupt: { + executor: 'shared-iterations', + iterations: 1, + vus: 1, + exec: "disrupt", + startTime: "0s", + }, + } + ``` + +
+ + Notice that the `disrupt` scenario uses a `shared-iterations` executor with one iteration and one `VU`. This setting ensures the `disrupt` function is executed only once. Executing this function multiples times concurrently may have unpredictable results. + +
+ + +## Executions + +
+ +The commands in this section assume the `xk6-disruptor` binary is available in your current directory. This location can change depending on the installation process and the platform. Refer to the [installation section](/javascript-api/xk6-disruptor/get-started/installation) for details on how to install it in your environment. + +
+ +### Baseline execution + +We will first execute the test without introducing faults to have an baseline using the following command: + + + +```bash +xk6-disruptor run --env SKIP_FAULTS=1 --env SVC_IP=$SVC_IP disrupt-pod.js +``` + +```PowerShell +xk6-disruptor run --env SKIP_FAULTS=1 --env "SVC_IP=$Env:SVC_IP" disrupt-pod.js +``` + + + + +Notice the argument `--env SKIP_FAULT=1`, which makes the `disrupt` function return without injecting any fault as explained in the [fault injection](#fault-injection) section. Also notice the `--env SVC_IP` argument, which passes the external IP used to access the `httpbin` application. + +You should get an output similar to the one shown below (click `Expand` button to see all output). + + + +``` + /\ |‾‾| /‾‾/ /‾‾/ + /\ / \ | |/ / / / + / \/ \ | ( / ‾‾\ + / \ | |\ \ | (‾) | + / __________ \ |__| \__\ \_____/ .io + + execution: local + script: test.js + output: - + + scenarios: (100.00%) 2 scenarios, 101 max VUs, 10m30s max duration (incl. graceful stop): + * disrupt: 1 iterations shared among 1 VUs (maxDuration: 10m0s, exec: disrupt, gracefulStop: 30s) + * load: 100.00 iterations/s for 30s (maxVUs: 10-100, exec: default, gracefulStop: 30s) + + +running (00m30.1s), 000/014 VUs, 2998 complete and 0 interrupted iterations +disrupt ✓ [======================================] 1 VUs 00m00.0s/10m0s 1/1 shared iters +load ✓ [======================================] 000/013 VUs 30s 100.00 iters/s + + data_received..................: 1.4 MB 46 kB/s + data_sent......................: 267 kB 8.9 kB/s + dropped_iterations.............: 4 0.132766/s + http_req_blocked...............: avg=8.08µs min=2.36µs med=5.8µs max=543.79µs p(90)=8.68µs p(95)=10.5µs + http_req_connecting............: avg=1.25µs min=0s med=0s max=418.63µs p(90)=0s p(95)=0s + http_req_duration..............: avg=103.22ms min=101.65ms med=103.13ms max=121.7ms p(90)=104.01ms p(95)=104.4ms + { expected_response:true }...: avg=103.22ms min=101.65ms med=103.13ms max=121.7ms p(90)=104.01ms p(95)=104.4ms + http_req_failed................: 0.00% ✓ 0 ✗ 2997 + http_req_receiving.............: avg=133.5µs min=45.06µs med=131.23µs max=879.43µs p(90)=193.48µs p(95)=223.04µs + http_req_sending...............: avg=31.14µs min=11.46µs med=29.37µs max=171.68µs p(90)=40.48µs p(95)=47.53µs + http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s + http_req_waiting...............: avg=103.05ms min=101.54ms med=102.98ms max=121.56ms p(90)=103.82ms p(95)=104.2ms + http_reqs......................: 2997 99.474844/s + iteration_duration.............: avg=103.34ms min=109.86µs med=103.28ms max=121.92ms p(90)=104.19ms p(95)=104.63ms + iterations.....................: 2998 99.508035/s + vus............................: 13 min=11 max=13 + vus_max........................: 14 min=12 max=14 +``` + + + + +### Fault injection + +We repeat the execution injecting the faults. Notice we have removed the `--env SKIP_FAULTS=1` argument. + + + +```bash +xk6-disruptor run --env SVC_IP=$SVC_IP disrupt-pod.js +``` + +```PowerShell +xk6-disruptor run --env "SVC_IP=$Env:SVC_IP" disrupt-pod.js +``` + + + + + +``` + + /\ |‾‾| /‾‾/ /‾‾/ + /\ / \ | |/ / / / + / \/ \ | ( / ‾‾\ + / \ | |\ \ | (‾) | + / __________ \ |__| \__\ \_____/ .io + + execution: local + script: disrupt-pod.js + output: - + + scenarios: (100.00%) 2 scenarios, 101 max VUs, 10m30s max duration (incl. graceful stop): + * disrupt: 1 iterations shared among 1 VUs (maxDuration: 10m0s, exec: disrupt, gracefulStop: 30s) + * load: 100.00 iterations/s for 30s (maxVUs: 10-100, exec: default, gracefulStop: 30s) + + +running (00m31.1s), 000/018 VUs, 2995 complete and 0 interrupted iterations +disrupt ✓ [======================================] 1 VUs 00m31.1s/10m0s 1/1 shared iters +load ✓ [======================================] 000/017 VUs 30s 100.00 iters/s + + data_received..................: 1.1 MB 34 kB/s + data_sent......................: 267 kB 8.6 kB/s + dropped_iterations.............: 7 0.224798/s + http_req_blocked...............: avg=9.81µs min=2.59µs med=5.93µs max=489.67µs p(90)=7.88µs p(95)=9.5µs + http_req_connecting............: avg=2.48µs min=0s med=0s max=367.63µs p(90)=0s p(95)=0s + http_req_duration..............: avg=142.15ms min=50.33ms med=153.79ms max=165.85ms p(90)=154.8ms p(95)=155.12ms + { expected_response:true }...: avg=151.9ms min=101.81ms med=153.9ms max=165.85ms p(90)=154.86ms p(95)=155.17ms + http_req_failed................: 9.65% ✓ 289 ✗ 2705 + http_req_receiving.............: avg=80.92µs min=28.32µs med=77.33µs max=352.19µs p(90)=105.09µs p(95)=123.68µs + http_req_sending...............: avg=30.43µs min=11.27µs med=29.37µs max=287.71µs p(90)=37.42µs p(95)=41.84µs + http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s + http_req_waiting...............: avg=142.04ms min=50.25ms med=153.68ms max=165.76ms p(90)=154.69ms p(95)=155.01ms + http_reqs......................: 2994 96.149356/s + iteration_duration.............: avg=152.64ms min=50.43ms med=153.93ms max=31.12s p(90)=154.97ms p(95)=155.29ms + iterations.....................: 2995 96.18147/s + vus............................: 1 min=1 max=18 + vus_max........................: 18 min=12 max=18 + +``` + + +### Comparison + +Let's take a closer look at the results for the requests on each scenario. We can observe that he `base` scenario has an average of `103ms` and an error rate of `0%` while the `faults` scenario has a median around `151.9ms` and an error rate of nearly `10%`, matching the definition of the faults defined in the disruptor. + +| Execution | Avg. Response | Failed requests | +| --------------- | ------------- | --------------- | +| Baseline | 103.22ms | 0.00% | +| Fault injection | 151.9 ms | 9.65% | + + +
+ +Notice we have used the average response time reported as `expected_response:true` because this metric only consider successful requests while `http_req_duration` considers all requests, including those returning a fault. + +
+ +## Source Code + + + +```javascript +import { PodDisruptor } from 'k6/x/disruptor'; +import http from 'k6/http'; + +export default function (data) { + http.get(`http://${__ENV.SVC_IP}/delay/0.1`); +} + +export function disrupt(data) { + if (__ENV.SKIP_FAULTS == "1") { + return + } + + const selector = { + namespace: "httpbin", + select: { + labels: { + app: "httpbin" + } + } + } + const podDisruptor = new PodDisruptor(selector) + + // delay traffic from one random replica of the deployment + const fault = { + averageDelay: "50ms", + errorCode: 500, + errorRate: 0.1 + } + podDisruptor.injectHTTPFaults(fault, "30s") +} + +export const options = { + scenarios: { + load: { + executor: 'constant-arrival-rate', + rate: 100, + preAllocatedVUs: 10, + maxVUs: 100, + exec: "default", + startTime: "0s", + duration: "30s", + }, + disrupt: { + executor: 'shared-iterations', + iterations: 1, + vus: 1, + exec: "disrupt", + startTime: "0s", + }, + } +} +``` + + + +## Test setup + +The tests requires the deployment of the `httpbin` application. The application must also be accessible using an external IP available in the `SVC_IP` environment variable. + +The [manifests](#manifests) below define the resources required for deploying the application and exposing it as a LoadBalancer service. + +You can deploy the application using the following commands: + +```bash +# Create Namespace +kubectl apply -f namespace.yaml +namespace/httpbin created + +# Deploy Pod +kubectl apply -f pod.yaml +pod/httpbin created + +# Expose Pod as a Service +kubectl apply -f service.yaml +service/httpbin created +``` + +You can retrieve the resources using the following command: + +```bash +kubectl -n httpbin get all +NAME READY STATUS RESTARTS AGE +pod/httpbin 1/1 Running 0 1m + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/httpbin LoadBalancer 10.96.169.78 172.18.255.200 80:31224/TCP 1m +``` + +You must set the environment variable `SVC_IP` with the external IP address and port used to access the `httpbin` service from the test script. + +You can learn more about how to get the external IP address in the [expose your application](/javascript-api/xk6-disruptor/get-started/expose-your-application) section. + + +### Manifests + + + +```yaml +apiVersion: "v1" +kind: Namespace +metadata: + name: httpbin +``` + + + + + +```yaml +kind: "Pod" +apiVersion: "v1" +metadata: + name: httpbin + namespace: httpbin + labels: + app: httpbin +spec: + containers: + - name: httpbin + image: kennethreitz/httpbin + ports: + - name: http + containerPort: 80 +``` + + + + + + +```yaml +apiVersion: "v1" +kind: "Service" +metadata: + name: httpbin + namespace: httpbin +spec: + selector: + app: httpbin + type: "LoadBalancer" + ports: + - port: 80 + targetPort: 80 +``` + + + diff --git a/src/data/markdown/docs/40 xk6-disruptor/04 Examples/03 demo-environment.md b/src/data/markdown/docs/40 xk6-disruptor/04 Examples/03 demo-environment.md new file mode 100644 index 0000000000..8435ee2a7b --- /dev/null +++ b/src/data/markdown/docs/40 xk6-disruptor/04 Examples/03 demo-environment.md @@ -0,0 +1,4 @@ +--- +title: 'Interactive demo' +redirect: 'https://killercoda.com/grafana-xk6-disruptor/scenario/killercoda' +--- \ No newline at end of file diff --git a/src/data/markdown/translated-guides/en/01 Get started/02 Installation.md b/src/data/markdown/translated-guides/en/01 Get started/02 Installation.md index 73005b0b5b..d5d706f7ed 100644 --- a/src/data/markdown/translated-guides/en/01 Get started/02 Installation.md +++ b/src/data/markdown/translated-guides/en/01 Get started/02 Installation.md @@ -2,7 +2,6 @@ title: 'Installation' excerpt: 'k6 has packages for Linux, Mac, and Windows. As alternatives, you can also using a Docker container or a standalone binary.' canonicalUrl: https://grafana.com/docs/k6/latest/set-up/install-k6/ -redirect: https://grafana.com/docs/k6/latest/set-up/install-k6/ --- k6 has packages for Linux, Mac, and Windows. Alternatively, you can use a Docker container or a standalone binary. diff --git a/src/data/markdown/translated-guides/en/01 Get started/02 Installation/01 Troubleshooting.md b/src/data/markdown/translated-guides/en/01 Get started/02 Installation/01 Troubleshooting.md new file mode 100644 index 0000000000..0e2cc9172c --- /dev/null +++ b/src/data/markdown/translated-guides/en/01 Get started/02 Installation/01 Troubleshooting.md @@ -0,0 +1,38 @@ +--- +title: 'Troubleshooting' +excerpt: 'Instructions to fix the most common installation issues.' +canonicalUrl: https://grafana.com/docs/k6/latest/set-up/install-k6/troubleshooting/ +--- + +## System lacks ca-certificates or gnupg2 + +Some Linux distributions don't come bundled with the `ca-certificates` and `gnupg2` packages. +If you use such a distribution, you'll need to install them with: + +```bash +sudo apt-get update && sudo apt-get install -y ca-certificates gnupg2 +``` + +This example is for Debian/Ubuntu and derivatives. Consult your distribution's documentation if you use another one. + + +## Behind a firewall or proxy + +Some users have reported that they can't download the key from Ubuntu's keyserver. +When they run the `gpg` command, their firewalls or proxies block their requests to download. +If this issue affects you, you can try this alternative: + + +```bash +curl -s https://dl.k6.io/key.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/k6-archive-keyring.gpg +``` + + +## Old rpm-based Linux distributions + +Distributions like Amazon Linux 2 and CentOS before version 8 don't support the PGP V4 signature we use. +You'll need to disable the verification when you install k6: + +```bash +sudo yum install --nogpgcheck k6 +``` diff --git a/src/data/markdown/translated-guides/en/01 Get started/03 Running k6.md b/src/data/markdown/translated-guides/en/01 Get started/03 Running k6.md index a7fb26501d..6f85eef30a 100644 --- a/src/data/markdown/translated-guides/en/01 Get started/03 Running k6.md +++ b/src/data/markdown/translated-guides/en/01 Get started/03 Running k6.md @@ -2,7 +2,6 @@ title: 'Running k6' excerpt: 'Follow along to learn how to run a test, add virtual users, increase the test duration, and ramp the number of requests up and down as the test runs.' canonicalUrl: https://grafana.com/docs/k6/latest/get-started/running-k6/ -redirect: https://grafana.com/docs/k6/latest/get-started/running-k6/ --- Follow along to learn how to: diff --git a/src/data/markdown/translated-guides/en/01 Get started/04 Results Output.md b/src/data/markdown/translated-guides/en/01 Get started/04 Results Output.md index 62a02742d6..e39b13457d 100644 --- a/src/data/markdown/translated-guides/en/01 Get started/04 Results Output.md +++ b/src/data/markdown/translated-guides/en/01 Get started/04 Results Output.md @@ -2,7 +2,6 @@ title: 'Results output' excerpt: 'For basic tests, the top-level summary that k6 provides might be enough. For detailed analysis, you can stream all data your test outputs to an external source.' canonicalUrl: https://grafana.com/docs/k6/latest/get-started/results-output/ -redirect: https://grafana.com/docs/k6/latest/get-started/results-output/ --- As k6 generates load for your test, it also makes _metrics_ that measure the performance of the system. diff --git a/src/data/markdown/translated-guides/en/01 Get started/05 resources.md b/src/data/markdown/translated-guides/en/01 Get started/05 resources.md index a9c69c6fb3..33b41eae34 100644 --- a/src/data/markdown/translated-guides/en/01 Get started/05 resources.md +++ b/src/data/markdown/translated-guides/en/01 Get started/05 resources.md @@ -3,7 +3,6 @@ title: k6 resources excerpt: 'An overview of the k6 resources beyond the k6 docs: videos, repositories, test servers, courses, and more' slug: '/get-started/resources/' canonicalUrl: https://grafana.com/docs/k6/latest/get-started/resources/ -redirect: https://grafana.com/docs/k6/latest/get-started/resources/ --- The docs aim to cover everything necessary to use the core k6 products in your daily operational work. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/01 HTTP requests.md b/src/data/markdown/translated-guides/en/02 Using k6/01 HTTP requests.md index 2d39197584..a7c646066e 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/01 HTTP requests.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/01 HTTP requests.md @@ -2,7 +2,6 @@ title: 'HTTP Requests' excerpt: 'Define the HTTP requests and methods you want to use. k6 adds tags to the requests, making it easier to filter results. You can customize tags as you wish.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/http-requests/ -redirect: https://grafana.com/docs/k6/latest/using-k6/http-requests/ --- When testers create new load test, the first step is often to define the HTTP requests to test the system with. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics.md b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics.md index 84293030ea..ac23dbdc40 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics.md @@ -2,7 +2,6 @@ title: 'Metrics' excerpt: 'This section covers the important aspect of metrics management in k6. How and what kind of metrics k6 collects automatically (_built-in_ metrics), and what custom metrics you can make k6 collect.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/metrics/ -redirect: https://grafana.com/docs/k6/latest/using-k6/metrics/ --- _Metrics_ measure how a system performs under test conditions. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md new file mode 100644 index 0000000000..3e826e6bca --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/000-reference.md @@ -0,0 +1,106 @@ +--- +title: Built-in metrics +slug: '/using-k6/metrics/reference' +excerpt: A reference of built-in metrics for different supported protocols. +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/metrics/reference/ +--- + +Every k6 test emits built-in and [Custom metrics](/using-k6/metrics/create-custom-metrics). +Each supported protocol also has its specific metrics. + +## Standard built-in metrics. + +k6 always collects the following metrics, no matter what protocol the test uses: + +| Metric Name | Type | Description | +|--------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| vus | Gauge | Current number of active virtual users | +| vus_max | Gauge | Max possible number of virtual users (VU resources are [pre-allocated](/using-k6/scenarios/concepts/arrival-rate-vu-allocation/), to avoid affecting performance when scaling up load ) | +| iterations | Counter | The aggregate number of times the VUs execute the JS script (the `default` function). | +| iteration_duration | Trend | The time to complete one full iteration, including time spent in `setup` and `teardown`. To calculate the duration of the iteration's function for the specific scenario, [try this workaround](/using-k6/workaround-to-calculate-iteration_duration) | +| dropped_iterations | Counter | The number of iterations that weren't started due to lack of VUs (for the arrival-rate executors) or lack of time (expired maxDuration in the iteration-based executors). [About dropped iterations](/using-k6/scenarios/concepts/dropped-iterations/) | +| data_received | Counter | The amount of received data. [This example covers how to track data for an individual URL](/examples/track-transmitted-data-per-url). | +| data_sent | Counter | The amount of data sent. [Track data for an individual URL](/examples/track-transmitted-data-per-url) to track data for an individual URL. | +| checks | Rate | The rate of successful checks. + +## HTTP-specific built-in metrics {#http} + +These metrics are generated only when the test makes HTTP requests. + +
+ +For all `http_req_*` metrics, **the timestamp is emitted the end of the request.** +In other words, the timestamp happens when k6 receives the end of the response body, or the request times out. + +
+ +| Metric Name | Type | Description | +|--------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| http_reqs | Counter | How many total HTTP requests k6 generated. | +| http_req_blocked | Trend | Time spent blocked (waiting for a free TCP connection slot) before initiating the request. `float` | +| http_req_connecting | Trend | Time spent establishing TCP connection to the remote host. `float` | +| http_req_tls_handshaking | Trend | Time spent handshaking TLS session with remote host | +| http_req_sending | Trend | Time spent sending data to the remote host. `float` | +| http_req_waiting | Trend | Time spent waiting for response from remote host (a.k.a. “time to first byte”, or “TTFB”). `float` | +| http_req_receiving | Trend | Time spent receiving response data from the remote host. `float` | +| http_req_duration | Trend | Total time for the request. It's equal to `http_req_sending + http_req_waiting + http_req_receiving` (i.e. how long did the remote server take to process the request and respond, without the initial DNS lookup/connection times). `float` | +| http_req_failed | Rate | The rate of failed requests according to [setResponseCallback](/javascript-api/k6-http/setresponsecallback). | + +## Browser metrics {#browser} + +The [k6 browser module](/using-k6-browser) emits its own metrics based on the [Core Web Vitals](https://web.dev/vitals/#core-web-vitals). + + +These core metrics will evolve over time when technology changes, but for now, k6 tracks the following core web vitals: + + +| Core Web Vital | Description | +|-----------------------|--------------------------------------------------------------------------------------------------------------| +| browser_web_vital_lcp | Measures a page's loading performance. Please refer to [Largest Contentful Paint](https://web.dev/lcp/) for more information. | +| browser_web_vital_fid | Measures a page's interactivity. Please refer to [First Input Delay](https://web.dev/fid/) for more information. | +| browser_web_vital_cls | Measures a page's visual stability. Please refer to [Cumulative Layout Shift](https://web.dev/cls/) for more information. | + + +### Other Web Vitals + +Apart from the Core Web Vitals, the browser module also reports [Other Web Vitals](https://web.dev/vitals/#other-web-vitals). + + +| Other Web Vital | Description | +|-------------------------------- |--------------------------------------------------------------------------------------------------------------| +| browser_web_vital_ttfb | Measures the time it takes between the browser request and the start of the response from a server. Please refer to [Time to First Byte](https://web.dev/ttfb/) for more information.| +| browser_web_vital_fcp | Measures the time it takes for the browser to render the first DOM element on the page, whether that's a text, image or header. Please refer to [First Contentful Paint](https://web.dev/fcp/) for more information. | +| browser_web_vital_inp | An experimental metric that measures a page's responsiveness. Please refer to [Interaction to Next Paint](https://web.dev/inp/) for more information. | + + + +## Built-in WebSocket metrics {#websockets} + +`k6` emits the following metrics when interacting with a WebSocket service through the [`experimental`](/javascript-api/k6-experimental/websockets) or legacy websockets API. + +| Metric name | Type | Description | +|---------------------|---------|--------------------------------------------------------------------------------------------------------------| +| ws_connecting | Trend | Total duration for the WebSocket connection request. | +| ws_session_duration | Trend | Duration of the WebSocket session. Time between the start of the connection and the end of the VU execution. | +| ws_sessions | Counter | Total number of started WebSocket sessions. | +| ws_ping | Trend | Duration between a ping request and its pong reception | +| ws_msgs_sent | Counter | Total number of messages sent | +| ws_msgs_received | Counter | Total number of messages received | + +## Built-in gRPC metrics {#grpc} + +k6 emits the following metrics when it interacts with a service through the [`gRPC`](https://k6.io/docs/javascript-api/k6-net-grpc/) API. + +| Metric Name | Type | Description | +|------------------------------|---------|-------------------------------------------| +| `grpc_req_duration` | Trend | Time to receive response from remote host | +| `grpc_streams` | Counter | Total number of started streams | +| `grpc_streams_msgs_sent` | Counter | Total number of messages sent | +| `grpc_streams_msgs_received` | Counter | Total number of messages received | + + +
+ +Steams-related metrics (`grpc_streams*`) are available only with using `k6/experimental/grpc` module which is available since `k6` version `0.45.0`. + +
\ No newline at end of file diff --git a/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/100 Create custom metrics.md b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/100 Create custom metrics.md new file mode 100644 index 0000000000..5b93684cf7 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/02 Metrics/100 Create custom metrics.md @@ -0,0 +1,106 @@ +--- +title: Create custom metrics +excerpt: How to build custom k6 metrics for each metric type. +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/metrics/create-custom-metrics/ +--- + +Besides the [built-in metrics](/using-k6/metrics/reference), you can create custom metrics. +For example, you can compute a metric for your business logic, or use the [Response.timings](/javascript-api/k6-http/response) object to create a metric for a specific set of endpoints. + +Each metric type has a [constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor) to create a custom metric. +The constructor creates a metric object of the declared type. Each type has an `add` method to take metric measurements. + +If you need help constructing a custom metric, read the following sections of this document. +They document the procedure and provide examples. +If you're comfortable with these already, you might prefer to read the [reference documentation for each metric constructor](/javascript-api/k6-metrics). +Each topic has examples to make a custom metric and create [thresholds](/using-k6/thresholds) from it. + +## Create a custom metric + +
+ +Custom metrics must be created in [init context](/using-k6/test-lifecycle). +This limits memory and ensures that k6 can validate that all thresholds are evaluating defined metrics. + +
+ +The generic procedure to create a custom metric is as follows: + +1. Import the [`k6/metrics`](/javascript-api/k6-metrics/) module. + Optionally, specify the type of metrics you want to create with a named import: + + ``` + import { Counter } from 'k6/metrics'; + ``` + +1. In init context, construct a new custom-metric object. + + For example, the following creates a custom trend. The object in the script is called `myTrend`, and its metric appears in the results output as `waiting_time`. + + ``` + const myTrend = new Trend('waiting_time'); + ``` + +1. In the VU iteration code, use the `add` method to take a measurement. + +## Example: create a trend metric for waiting time + +This VU code makes a request then adds the timing value of the request to the `myTrend` object. + + + +```javascript +import http from 'k6/http'; +import { Trend } from 'k6/metrics'; + +const myTrend = new Trend('waiting_time'); + +export default function () { + const r = http.get('https://httpbin.test.k6.io'); + myTrend.add(r.timings.waiting); + console.log(myTrend.name); // waiting_time +} +``` + + + +## View custom metric results + +Custom metrics appear in [Results output](/results-output) in both the end-of-test summary and in the granular data points. +Each metric type has specific aggregation methods. +You can also optionally [tag](/using-k6/tags-and-groups) any value for a custom metric. +You can use these tags to filter test results. + +Here's how the output of the preceding script might look in the end-of-test summary. +Since the metric is a trend, k6 calculates various trends based on the number of values and their summation. + + + +```bash +$ k6 run script.js + + ... + INFO[0001] waiting_time source=console + + ... + iteration_duration.............: avg=1.15s min=1.15s med=1.15s max=1.15s p(90)=1.15s p(95)=1.15s + iterations.....................: 1 0.864973/s + waiting_time...................: avg=265.245396 min=265.245396 med=265.245396 max=265.245396 p(90)=265.245396 p(95)=265.245396 +``` + + + +
+ +Custom metrics are collected from VU threads only at the end of a VU iteration. +For long-running scripts, custom metrics might appear only after the test runs a while. + +
+ +## Read more + +The [`k6/metrics`](/javascript-api/k6-metrics/) has examples for defining each type of custom metric, and for defining a threshold on the metric. +- [Counter](/javascript-api/k6-metrics/counter) +- [Gauge](/javascript-api/k6-metrics/gauge) +- [Rate](/javascript-api/k6-metrics/rate) +- [Trend](/javascript-api/k6-metrics/trend) diff --git a/src/data/markdown/translated-guides/en/02 Using k6/03 Checks.md b/src/data/markdown/translated-guides/en/02 Using k6/03 Checks.md index c707c2c2fc..d64d138d9e 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/03 Checks.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/03 Checks.md @@ -2,7 +2,6 @@ title: 'Checks' excerpt: 'Checks are like asserts but differ in that they do not halt the execution, instead, they just store the result of the check, pass or fail, and let the script execution continue.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/checks/ -redirect: https://grafana.com/docs/k6/latest/using-k6/checks/ --- Checks validate boolean conditions in your test. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/04 Thresholds.md b/src/data/markdown/translated-guides/en/02 Using k6/04 Thresholds.md index 766a927146..2fb87b57cd 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/04 Thresholds.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/04 Thresholds.md @@ -2,7 +2,6 @@ title: 'Thresholds' excerpt: 'Thresholds are a pass/fail criteria used to specify the performance expectations of the system under test.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/thresholds/ -redirect: https://grafana.com/docs/k6/latest/using-k6/thresholds/ --- Thresholds are the pass/fail criteria that you define for your test metrics. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options.md b/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options.md index b04da822b9..f2625db5b8 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options.md @@ -3,7 +3,6 @@ title: 'Options' slug: '/using-k6/k6-options' excerpt: 'Options configure test-run behavior. You can set options in multiple locations. Examples for how to use options, and a complete reference.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/k6-options/ -redirect: https://grafana.com/docs/k6/latest/using-k6/k6-options/ --- Options configure test-run behavior. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options/01 How to.md b/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options/01 How to.md new file mode 100644 index 0000000000..15317c3007 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options/01 How to.md @@ -0,0 +1,227 @@ +--- +title: 'How to use options' +slug: '/using-k6/k6-options/how-to' +excerpt: 'How to set options in different places (with examples), how to override options, and how to access the value of an option as the test runs.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/k6-options/how-to/ +--- + +k6 provides multiple places to set options: + +- In CLI flags +- In environment variables +- In the script `options` object +- In a configuration file + +Most likely, your use case will determine where you want to set the particular options for a particular test. +You can also access option values as your test runs. + +## Order of precedence {#order-of-precedence} + +![Options passed as command-line flags override all other options: defaults < script options < environment variables < command-line flags](../images/Options/order-of-precedence.png) + +You can set options in multiple places. +If there are conflicts, k6 uses the option from the place with the highest _order of precedence_. + +1. First, k6 uses the option's default value. +1. Next, k6 uses the options set in a configuration file via the `--config` flag. +1. Then, k6 uses the script value (if set). +1. After, k6 uses the environment variable (if set). +1. Finally, k6 takes the value from the CLI flag (if set). + +That is, **command-line flags have the highest order of precedence**. + +## Where to set options + +Sometimes, how you set options is a matter of personal preference. +Other times, the context of your test dictates the most sensible place to put your options. + + + +Options in the script to version control and keep tests tidy. +: The script `options` object is generally the best place to put your options. +This provides automatic version control, allows for easy reuse, and lets you modularize your script. + +CLI flags to set options on the fly +: When you want to run a quick test, command-line flags are convenient. +: You can also use command-line flags to override files in your script (as determined by the [order of precedence](#order-of-precedence)). + For example, if your script file sets the test duration at 60 seconds, you could use a CLI flag to run a one-time shorter test. + With a flag like `--duration 30s`, the test would be half as long but otherwise identical. + +Environment variables to set options from your build chain +: For example, you could derive the option from a variable in your Docker container definition, CI UI, or vault—wherever you declare environment variables. +: The [block hostnames](/using-k6/k6-options/reference#block-hostnames) option is an example of an option that works well with environment variables. + + + +## Examples of setting options + +The following JS snippets show some examples of how you can set options. + +### Set options in the script + + + +```javascript +import http from 'k6/http'; + +export const options = { + hosts: { 'test.k6.io': '1.2.3.4' }, + stages: [ + { duration: '1m', target: 10 }, + { duration: '1m', target: 20 }, + { duration: '1m', target: 0 }, + ], + thresholds: { http_req_duration: ['avg<100', 'p(95)<200'] }, + noConnectionReuse: true, + userAgent: 'MyK6UserAgentString/1.0', +}; + +export default function () { + http.get('http://test.k6.io/'); +} +``` + + + + +### Set options with environment variables + +You can also set the options from the previous example through environment variables and command-line flags: + + + +```bash +$ K6_NO_CONNECTION_REUSE=true K6_USER_AGENT="MyK6UserAgentString/1.0" k6 run script.js + +$ k6 run --no-connection-reuse --user-agent "MyK6UserAgentString/1.0" script.js +``` + +```bash +C:\k6> set "K6_NO_CONNECTION_REUSE=true" && set "K6_USER_AGENT=MyK6UserAgentString/1.0" && k6 run script.js + +C:\k6> k6 run --no-connection-reuse --user-agent "MyK6UserAgentString/1.0" script.js +``` + +```bash +PS C:\k6> $env:K6_NO_CONNECTION_REUSE=true; $env:K6_USER_AGENT="MyK6UserAgentString/1.0"; k6 run script.js + +PS C:\k6> k6 run --no-connection-reuse --user-agent "MyK6UserAgentString/1.0" script.js +``` + + + +### Set options from k6 variables + +With the `--env` flag, you can use the CLI to define k6 variables. +Then, you can use the variable to dynamically define an option's value in the script file. + +For example, you could define a variable for your user agent like this: + +``` +k6 run script.js --env MY_USER_AGENT="hello" +``` + +Then, your script could then set the `userAgent` option based on the variable's value. +This allows for quick configuration. + + + +```javascript +import http from 'k6/http'; + +export const options = { + userAgent: __ENV.MY_USER_AGENT, +}; + +export default function () { + http.get('http://test.k6.io/'); +} +``` + + + +> **Note**: Though this method uses the `--env` flag, this is not the same as using an environment variable. +> For an explanation, refer to the [environment variables document](/using-k6/environment-variables). + +### Set options with the --config flag + +k6 includes a [default configuration file](/using-k6/k6-options/reference/#config) that you can edit, or you can create a new file and then use a CLI flag to point to that file. +If you use it, the options take the _second lowest order of precedence_ (after defaults). +If you set options anywhere else, they will override the `--config` flag options. + +Use the `--config` flag to declare the file path to your options. + +```bash +k6 run --config options.json script.js +``` + +This command would set test options according to the values in the `options.json` file. + + + +```json +{ + "hosts": { + "test.k6.io": "1.2.3.4" + }, + "stages": [ + { + "duration": "1m", + "target": 10 + }, + { + "duration": "1m", + "target": 30 + }, + { + "duration": "1m", + "target": 0 + } + ], + "thresholds": { + "http_req_duration": ["avg<100", "p(95)<200"] + }, + "noConnectionReuse": true, + "userAgent": "MyK6UserAgentString/1.0" +} +``` + + + +For an alternative way to separate configuration from logic, you can use the `JSON.parse()` method in your script file: + +```javascript +// load test config, used to populate exported options object: +const testConfig = JSON.parse(open('./config/test.json')); +// combine the above with options set directly: +export const options = testConfig; +``` + +## Get an option value from the script + +The `k6/execution` API provides a [test.options](/javascript-api/k6-execution/#test) object. +With `test.options`, you can access the consolidated and derived options of your script as the test runs. + +A common use of this feature is to log the value of a tag, but there are many possibilities. +For example, this script accesses the value of the test's current stage: + + + +```javascript +import exec from 'k6/execution'; + +export const options = { + stages: [ + { duration: '5s', target: 100 }, + { duration: '5s', target: 50 }, + ], +}; + +export default function () { + console.log(exec.test.options.scenarios.default.stages[0].target); // 100 +} +``` + + + +
diff --git a/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options/02 Reference.md b/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options/02 Reference.md new file mode 100644 index 0000000000..2b10b27bb3 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/05 k6 Options/02 Reference.md @@ -0,0 +1,1507 @@ +--- +title: 'Options reference' +slug: '/using-k6/k6-options/reference' +excerpt: 'A complete list of all k6 options, with descriptions, defaults, and examples of how to set the option in your script, config files, environment variables, or CLI.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/ +--- + +Options define test-run behavior. +Most options can be passed in multiple places. +If an option is defined in multiple places, k6 chooses the value from the highest [order of precedence](/using-k6/k6-options/how-to#order-of-precedence). + +## Quick reference of options + +Each option has its own detailed reference in a separate section. + +| Option | Description | +| --------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| [Address](#address) | Address of the REST API server | +| [Batch](#batch) | Max number of simultaneous connections of a `http.batch()` call | +| [Batch per host](#batch-per-host) | Max number of simultaneous connections of a `http.batch()` call for a host | +| [Blacklist IP](#blacklist-ip) | Blacklist IP ranges from being called | +| [Block hostnames](#block-hostnames) | Block any requests to specific hostnames | +| [Compatibility mode](#compatibility-mode) | Support running scripts with different ECMAScript modes | +| [Config](#config) | Specify the config file in JSON format to read the options values | +| [Console output](#console-output) | Redirects logs logged by `console` methods to the provided output file | +| [Discard response bodies](#discard-response-bodies) | Specify whether response bodies should be discarded | +| [DNS](#dns) | Configure DNS resolution behavior | +| [Duration](#duration) | A string specifying the total duration of the test run; together with the [vus option](#vus), it's a shortcut for a single [scenario](/using-k6/scenarios) with a [constant VUs executor](/using-k6/scenarios/executors/constant-vus) | +| [Execution segment](#execution-segment) | Limit execution to a segment of the total test | +| [Exit on running](#exit-on-running) | Exits when test reaches the running status | +| [Extension options](#extension-options) | An object used to set configuration options for cloud parameters and third-party collectors | +| [Hosts](#hosts) | An object with overrides to DNS resolution | +| [HTTP debug](#http-debug) | Log all HTTP requests and responses | +| [Include system Env vars](#include-system-env-vars) | Pass the real system environment variables to the runtime | +| [Insecure skip TLS verify](#insecure-skip-tls-verify) | A boolean specifying whether k6 should ignore TLS verifications for connections established from code | +| [Iterations](#iterations) | A number specifying a fixed number of iterations to execute of the script; together with the [vus option](#vus), it's a shortcut for a single [scenario](/using-k6/scenarios) with a [shared iterations executor](/using-k6/scenarios/executors/shared-iterations) | +| [Linger](#linger) | A boolean specifying whether k6 should linger around after test run completion | +| [Local IPs](#local-ips) | A list of local IPs, IP ranges, and CIDRs from which VUs will make requests | +| [Log output](#log-output) | Configuration about where logs from k6 should be send | +| [LogFormat](#logformat) | Specify the format of the log output | +| [Max redirects](#max-redirects) | The maximum number of HTTP redirects that k6 will follow | +| [Minimum iteration duration](#minimum-iteration-duration) | Specify the minimum duration for every single execution | +| [No color](#no-color) | A boolean specifying whether colored output is disabled | +| [No connection reuse](#no-connection-reuse) | A boolean specifying whether k6 should disable keep-alive connections | +| [No cookies reset](#no-cookies-reset) | This disables resetting the cookie jar after each VU iteration | +| [No summary](#no-summary) | disables the [end-of-test summary](/results-output/end-of-test/) | +| [No setup](#no-setup) | A boolean specifying whether `setup()` function should be run | +| [No teardown](#no-teardown) | A boolean specifying whether `teardown()` function should be run | +| [No thresholds](#no-thresholds) | Disables threshold execution | +| [No usage report](#no-usage-report) | A boolean specifying whether k6 should send a usage report | +| [No VU connection reuse](#no-vu-connection-reuse) | A boolean specifying whether k6 should reuse TCP connections | +| [Paused](#paused) | A boolean specifying whether the test should start in a paused state | +| [Quiet](#quiet) | A boolean specifying whether to show the progress update in the console or not | +| [Results output](#results-output) | Specify the results output | +| [RPS](#rps) | The maximum number of requests to make per second globally (discouraged, use [arrival-rate executors](/using-k6/scenarios/concepts/open-vs-closed) instead) | +| [Scenarios](#scenarios) | Define advanced execution scenarios | +| [Setup timeout](#setup-timeout) | Specify how long the `setup()` function is allow to run before it's terminated | +| [Show logs](#show-logs) | A boolean specifying whether the cloud logs are printed out to the terminal | +| [Stages](#stages) | A list of objects that specify the target number of VUs to ramp up or down; shortcut option for a single [scenario](/using-k6/scenarios) with a [ramping VUs executor](/using-k6/scenarios/executors/ramping-vus) | +| [Supply environment variable](#supply-environment-variables) | Add/override environment variable with `VAR=value` | +| [System tags](#system-tags) | Specify which System Tags will be in the collected metrics | +| [Summary export](#summary-export) | Output the [end-of-test summary](/results-output/end-of-test) report to a JSON file (discouraged, use [handleSummary()](/results-output/end-of-test/custom-summary) instead) | +| [Summary trend stats](#summary-trend-stats) | Define stats for trend metrics in the [end-of-test summary](/results-output/end-of-test) | +| [Summary time unit](#summary-time-unit) | Time unit to be used for _all_ time values in the [end-of-test summary](/results-output/end-of-test) | +| [Tags](#tags) | Specify tags that should be set test-wide across all metrics | +| [Teardown timeout](#teardown-timeout) | Specify how long the teardown() function is allowed to run before it's terminated | +| [Thresholds](#thresholds) | Configure under what conditions a test is successful or not | +| [Throw](#throw) | A boolean specifying whether to throw errors on failed HTTP requests | +| [TLS auth](#tls-auth) | A list of TLS client certificate configuration objects | +| [TLS cipher suites](#tls-cipher-suites) | A list of cipher suites allowed to be used by in SSL/TLS interactions with a server | +| [TLS version](#tls-version) | String or object representing the only SSL/TLS version allowed | +| [User agent](#user-agent) | A string specifying the User-Agent header when sending HTTP requests | +| [Verbose](#verbose) | A boolean specifying whether verbose logging is enabled | +| [VUs](#vus) | A number specifying the number of VUs to run concurrently | + +The following sections detail all available options that you can be specify within a script. + +It also documents the equivalent command line flag, environment variables or option when executing `k6 run ...` +and `k6 cloud ...`, which you can use to override options specified in the code. + +## Address + +Address of the API server. When executing scripts with `k6 run` an HTTP server with a REST API is spun up, +which can be used to control some of the parameters of the test execution. +By default, the server listens on `localhost:6565`. Read more on [k6 REST API](/misc/k6-rest-api). + +| Env | CLI | Code / Config file | Default | +| --- | ----------------- | ------------------ | ---------------- | +| N/A | `--address`, `-a` | N/A | `localhost:6565` | + + + +```bash +$ k6 run --address "localhost:3000" script.js +``` + + + +## Batch + +The maximum number of simultaneous/parallel connections in total that an +[`http.batch()`](/javascript-api/k6-http/batch) call in a VU can make. If you have a +`batch()` call that you've given 20 URLs to and `--batch` is set to 15, then the VU will make 15 +requests right away in parallel and queue the rest, executing them as soon as a previous request is +done and a slot opens. Available in both the `k6 run` and the `k6 cloud` commands + +| Env | CLI | Code / Config file | Default | +| ---------- | --------- | ------------------ | ------- | +| `K6_BATCH` | `--batch` | `batch` | `20` | + + + +```javascript +export const options = { + batch: 15, +}; +``` + + + +## Batch per host + +The maximum number of simultaneous/parallel connections for the same hostname that an +[`http.batch()`](/javascript-api/k6-http/batch) call in a VU can make. If you have a +`batch()` call that you've given 20 URLs to the _same_ hostname and `--batch-per-host` is set to 5, then the VU will make 5 +requests right away in parallel and queue the rest, executing them as soon as a previous request is +done and a slot opens. This will not run more request in parallel then the value of `batch`. Available in both the `k6 run` and the `k6 cloud` commands + +| Env | CLI | Code / Config file | Default | +| ------------------- | ------------------ | ------------------ | ------- | +| `K6_BATCH_PER_HOST` | `--batch-per-host` | `batchPerHost` | `6` | + + + +```javascript +export const options = { + batchPerHost: 5, +}; +``` + + + +## Blacklist IP + +Blacklist IP ranges from being called. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| ------------------ | ---------------- | ------------------ | ------- | +| `K6_BLACKLIST_IPS` | `--blacklist-ip` | `blacklistIPs` | `null` | + + + +```javascript +export const options = { + blacklistIPs: ['10.0.0.0/8'], +}; +``` + + + + +## Block hostnames + +Blocks hostnames based on a list of glob match strings. The pattern matching string can have a single +`*` at the beginning such as `*.example.com` that will match anything before that such as +`test.example.com` and `test.test.example.com`. +Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| -------------------- | ------------------- | ------------------ | ------- | +| `K6_BLOCK_HOSTNAMES` | `--block-hostnames` | `blockHostnames` | `null` | + + + +```javascript +export const options = { + blockHostnames: ['test.k6.io', '*.example.com'], +}; +``` + + + + + + +```bash +$ k6 run --block-hostnames="test.k6.io,*.example.com" script.js +``` + + + +## Compatibility mode + +Support running scripts with different ECMAScript compatibility modes. + +Read about the different modes on the [JavaScript Compatibility Mode documentation](/using-k6/javascript-compatibility-mode). + +| Env | CLI | Code / Config file | Default | +| ----------------------- | ---------------------- | ------------------ | ------------ | +| `K6_COMPATIBILITY_MODE` | `--compatibility-mode` | N/A | `"extended"` | + + + +```bash +$ k6 run --compatibility-mode=base script.js +``` + + + +## Config + +Specify the config file in JSON format. +If the config file is not specified, k6 looks for `config.json` in the `loadimpact/k6` directory inside the regular directory for configuration files on the operating system. +Default config locations on different operating systems are as follows: + +|OS|Default Config Path| +|---|---| +|Unix-based|`${HOME}/.config/loadimpact/k6/config.json`| +|macOS|`${HOME}/Library/Application Support/loadimpact/k6/config.json`| +|Windows|`%AppData%/loadimpact/k6/config.json`| + +Available in `k6 run` and `k6 cloud` commands: + +| Env | CLI | Code / Config file | Default | +| --- | ------------------------------ | ------------------ | ------- | +| N/A | `--config `, `-c ` | N/A | `null` | + +
+ +When running tests in k6 Cloud and using a non-default config.json file, +specify the cloud token inside your config file to authenticate. + +
+ + +## Console output + +Redirects logs logged by `console` methods to the provided output file. Available in `k6 cloud` and `k6 run` commands. + +| Env | CLI | Code / Config file | Default | +| --- | -------------------| ------------------ | ------- | +| `K6_CONSOLE_OUTPUT` | `--console-output` | N/A | `null` | + + + + +```bash +$ k6 run --console-output "loadtest.log" script.js +``` + + + +## Discard response bodies + +Specify if response bodies should be discarded by changing the default value of +[responseType](/javascript-api/k6-http/params) to `none` for all HTTP requests. Highly recommended to be set +to `true` and then only for the requests where the response body is needed for scripting +to set [responseType](/javascript-api/k6-http/params) to `text` or `binary`. Lessens the amount of memory +required and the amount of GC - reducing the load on the testing machine, and probably producing +more reliable test results. + +| Env | CLI | Code / Config file | Default | +| ---------------------------- | --------------------------- | ----------------------- | ------- | +| `K6_DISCARD_RESPONSE_BODIES` | `--discard-response-bodies` | `discardResponseBodies` | `false` | + + + +```javascript +export const options = { + discardResponseBodies: true, +}; +``` + + + +## DNS + +This is a composite option that provides control of DNS resolution behavior with +configuration for cache expiration (TTL), IP selection strategy and IP version +preference. The TTL field in the DNS record is currently not read by k6, so the +`ttl` option allows manual control over this behavior, albeit as a fixed value +for the duration of the test run. + +Note that DNS resolution is done only on new HTTP connections, and by default k6 +will try to reuse connections if HTTP keep-alive is supported. To force a certain +DNS behavior consider enabling the [`noConnectionReuse`](#no-connection-reuse) +option in your tests. + + +| Env | CLI | Code / Config file | Default | +| ---------| --------| -------------------| ---------------------------------------- | +| `K6_DNS` | `--dns` | `dns` | `ttl=5m,select=random,policy=preferIPv4` | + +Possible `ttl` values are: +- `0`: no caching at all - each request will trigger a new DNS lookup. +- `inf`: cache any resolved IPs for the duration of the test run. +- any time duration like `60s`, `5m30s`, `10m`, `2h`, etc.; if no unit is specified (e.g. `ttl=3000`), k6 assumes milliseconds. + +Possible `select` values are: +- `first`: always pick the first resolved IP. +- `random`: pick a random IP for every new connection. +- `roundRobin`: iterate sequentially over the resolved IPs. + +Possible `policy` values are: +- `preferIPv4`: use IPv4 addresses if available, otherwise fall back to IPv6. +- `preferIPv6`: use IPv6 addresses if available, otherwise fall back to IPv4. +- `onlyIPv4`: only use IPv4 addresses, ignore any IPv6 ones. +- `onlyIPv6`: only use IPv6 addresses, ignore any IPv4 ones. +- `any`: no preference, use all addresses. + +Here are some configuration examples: + +```bash +K6_DNS="ttl=5m,select=random,policy=preferIPv4" k6 cloud script.js +``` + + + +```javascript +export const options = { + dns: { + ttl: '1m', + select: 'roundRobin', + policy: 'any', + }, +}; +``` + + + +## Duration + +A string specifying the total duration a test run should be run for. During this time each +VU will execute the script in a loop. Available in `k6 run` and `k6 cloud` commands. + +Together with the [`vus` option](#vus), `duration` is a shortcut for a single [scenario](/using-k6/scenarios) with a [constant VUs executor](/using-k6/scenarios/executors/constant-vus). + +| Env | CLI | Code / Config file | Default | +| ------------- | ------------------ | ------------------ | ------- | +| `K6_DURATION` | `--duration`, `-d` | `duration` | `null` | + + + +```javascript +export const options = { + vus: 100, + duration: '3m', +}; +``` + + + +## Extension options + +An object used to set configuration options for cloud parameters and third-party collectors, like plugins. For more information about available parameters, refer to [Cloud options](/cloud/creating-and-running-a-test/cloud-scripting-extras/cloud-options/). + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | ------- | +| N/A | N/A | `ext` | `null` | + +This is an example of how to specify the test name (test runs/executions with the same name will be +logically grouped for trending and comparison) when streaming results to +[k6 Cloud Performance Insights](/cloud/analyzing-results/performance-insights). + + + +```javascript +export const options = { + ext: { + loadimpact: { + name: 'My test name', + }, + }, +}; +``` + + + +## Execution segment + +These options specify how to partition the test run and which segment to run. +If defined, k6 will scale the number of VUs and iterations to be run for that +segment, which is useful in distributed execution. Available in `k6 run` and +`k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | ------------------------------ | -------------------------- | ------- | +| N/A | `--execution-segment` | `executionSegment` | `"0:1"` | +| N/A | `--execution-segment-sequence` | `executionSegmentSequence` | `"0,1"` | + +For example, to run 25% of a test, you would specify `--execution-segment '25%'`, +which would be equivalent to `--execution-segment '0:1/4'`, i.e. run the first +1/4 of the test. +To ensure that each instance executes a specific segment, also specify the full +segment sequence, e.g. `--execution-segment-sequence '0,1/4,1/2,1'`. +This way one instance could run with `--execution-segment '0:1/4'`, another with +`--execution-segment '1/4:1/2'`, etc. and there would be no overlap between them. + + + +## Exit on running + +A boolean, specifying whether the script should exit once the test status reaches `running`. +When running scripts with `k6 cloud` by default scripts will run until the test reaches a finalized status. +This could be problematic in certain environments (think of Continuous Integration and Delivery pipelines), +since you'd need to wait until the test ends up in a finalized state. + +With this option, you can exit early and let the script run in the background. Available in `k6 cloud` command. + +| Env | CLI | Code / Config file | Default | +| -------------------- | ------------------- | ------------------ | ------- | +| `K6_EXIT_ON_RUNNING` | `--exit-on-running` | N/A | `false` | + + + +```bash +$ k6 cloud --exit-on-running script.js +``` + + + +## Hosts + +An object with overrides to DNS resolution, similar to what you can do with `/etc/hosts` on +Linux/Unix or `C:\Windows\System32\drivers\etc\hosts` on Windows. For instance, you could set +up an override which routes all requests for `test.k6.io` to `1.2.3.4`. + +k6 also supports ways to narrow or widen the scope of your redirects: +- You can redirect only from or to certain ports. +- Starting from v0.42.0, you can use an asterisk (`*`) as a wild card at the start of the host name to avoid repetition. For example, `*.k6.io` would apply the override for all subdomains of `k6.io`. + +
+ +This does not modify the actual HTTP `Host` header, but rather where it will be routed. + +
+ + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | ------- | +| N/A | N/A | `hosts` | `null` | + + + +```javascript +export const options = { + hosts: { + 'test.k6.io': '1.2.3.4', + 'test.k6.io:443': '1.2.3.4:8443', + '*.grafana.com': '1.2.3.4', + }, +}; +``` + + + +The preceding code will redirect requests made to `test.k6.io` to `1.2.3.4`, keeping the same port. If the request is done to port `443`, it will redirect it to port `8443` instead. It will also redirect requests to any subdomain of `grafana.com` to `1.2.3.4`. + +## HTTP debug + +Log all HTTP requests and responses. Excludes body by default, to include body use +`--http-debug=full`. Available in `k6 run` and `k6 cloud` commands. + +Read more [here](/using-k6/http-debugging). + +| Env | CLI | Code / Config file | Default | +| --------------- | --------------------------------------- | ------------------ | ------- | +| `K6_HTTP_DEBUG` | `--http-debug`,
`--http-debug=full` | `httpDebug` | `false` | + + + +```javascript +export const options = { + httpDebug: 'full', +}; +``` + + + +## Include system env vars + +Pass the real system [environment variables](/using-k6/environment-variables) to the runtime. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | --------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------- | +| N/A | `--include-system-env-vars` | N/A | `true` for `k6 run`, but `false` for all other commands to prevent inadvertent sensitive data leaks. | + + + +```bash +$ k6 run --include-system-env-vars ~/script.js +``` + + + +## Insecure skip TLS verify + +A boolean, true or false. When this option is enabled (set to true), all of the verifications that +would otherwise be done to establish trust in a server provided TLS certificate will be ignored. +This only applies to connections created from code, such as HTTP requests. +Available in `k6 run` and `k6 cloud` commands + +| Env | CLI | Code / Config file | Default | +| ----------------------------- | ---------------------------- | ----------------------- | ------- | +| `K6_INSECURE_SKIP_TLS_VERIFY` | `--insecure-skip-tls-verify` | `insecureSkipTLSVerify` | `false` | + + + +```javascript +export const options = { + insecureSkipTLSVerify: true, +}; +``` + + + +## Iterations + +An integer value, specifying the total number of iterations of the `default` function to execute in the test run, as opposed to specifying a duration of time during which the script would run in a loop. Available both in the `k6 run` and `k6 cloud` commands. + +Together with the [`vus` option](#vus), `iterations` is a shortcut for a single [scenario](/using-k6/scenarios) with a [shared iterations executor](/using-k6/scenarios/executors/shared-iterations). + +By default, the maximum duration of a `shared-iterations` scenario is 10 minutes. You can adjust that time via the `maxDuration` option of the scenario, or by also specifying the [`duration` global shortcut option](#duration). + +**Note that iterations aren't fairly distributed with this option, and a VU that executes faster will complete more iterations than others.** Each VU will try to complete as many iterations as possible, ["stealing"](https://en.wikipedia.org/wiki/Work_stealing) them from the total number of iterations for the test. So, depending on iteration times, some VUs may complete more iterations than others. If you want guarantees that every VU will complete a specific, fixed number of iterations, [use the per-VU iterations executor](/using-k6/scenarios/executors/per-vu-iterations). + + +| Env | CLI | Code / Config file | Default | +| --------------- | -------------------- | ------------------ | ------- | +| `K6_ITERATIONS` | `--iterations`, `-i` | `iterations` | `1` | + + + +```javascript +export const options = { + vus: 5, + iterations: 10, +}; +``` + + + +Or, to run 10 VUs 10 times each: + + + +```javascript +export const options = { + vus: 10, + iterations: 100, +}; +``` + + + +## Linger + +A boolean, true or false, specifying whether the k6 process should linger around after test +run completion. Available in the `k6 run` command. + +| Env | CLI | Code / Config file | Default | +| ----------- | ---------------- | ------------------ | ------- | +| `K6_LINGER` | `--linger`, `-l` | `linger` | `false` | + + + +```javascript +export const options = { + linger: true, +}; +``` + + + +## Local IPs + +A list of IPs, IP ranges and CIDRs from which VUs will make requests. The IPs will be sequentially +given out to VUs. This option doesn't change anything on the OS level so the IPs need to be already +configured on the OS level for k6 to use them. Also IPv4 CIDRs with more than 2 +IPs don't include the first and last IP as they are reserved for referring to the network itself and +the broadcast address respectively. + +This option can be used for splitting the network traffic from k6 between multiple network cards, thus potentially increasing the available network throughput. For example, if you have 2 NICs, you can run k6 with `--local-ips=","` to balance the traffic equally between them - half of the VUs will use the first IP and the other half will use the second. This can scale to any number of NICs, and you can repeat some local IPs to give them more traffic. For example, `--local-ips=",,,"` will split VUs between 3 different source IPs in a 25%:25%:50% ratio. + +Available in the `k6 run` command. + +| Env | CLI | Code / Config file | Default | +| -------------- | ---------------- | ------------------ | ------- | +| `K6_LOCAL_IPS` | `--local-ips` | N/A | N/A | + + + + +```bash +$ k6 run --local-ips=192.168.20.12-192.168.20.15,192.168.10.0/27 script.js +``` + + + +## Log output + +This option specifies where to send logs to and another configuration connected to it. Available in the `k6 run` command. + +| Env | CLI | Code / Config file | Default | +| --------------- | -------------- | ------------------ | -------- | +| `K6_LOG_OUTPUT` | `--log-output` | N/A | `stderr` | + + + +```bash +$ k6 run --log-output=stdout script.js +``` + + + +Possible values are: + +- none - disable +- stdout - send to the standard output +- stderr - send to the standard error output (this is the default) +- loki - send logs to a loki server +- file - write logs to a file + +### Loki + +Use the `log-output` option to configure [Loki](https://grafana.com/oss/loki/) as follows. +For additional instructions and a step-by-step guide, check out the [Loki tutorial](https://k6.io/blog/using-loki-to-store-and-query-k6-logs/). + + + +```bash +$ k6 run --log-output=loki=http://127.0.0.1:3100/loki/api/v1/push,label.something=else,label.foo=bar,limit=32,level=info,pushPeriod=5m32s,msgMaxSize=1231 script.js +``` + + + +Where all but the url in the beginning are not required. +The possible keys with their meanings and default values: + +| key | description | default value | +| --- | ----------- | ------------- | +| `nothing` | the endpoint to which to send logs | `http://127.0.0.1:3100/loki/api/v1/push` | +| allowedLabels | if set k6 will send only the provided labels as such and all others will be appended to the message in the form `key=value`. The value of the option is in the form `[label1,label2]` | N/A | +| label.`labelName` | adds an additional label with the provided key and value to each message | N/A | +| header.`headerName` | adds an additional HTTP header with the provided header name and value to each HTTP request made to Loki | N/A | +| limit | the limit of message per pushPeriod, an additional log is send when the limit is reached, logging how many logs were dropped | 100 | +| level | the minimal level of a message so it's send to loki | all | +| pushPeriod | at what period to send log lines | 1s | +| profile | whether to print some info about performance of the sending to loki | false | +| msgMaxSize | how many symbols can there be at most in a message. Messages bigger will miss the middle of the message with an additional few characters explaining how many characters were dropped. | 1048576 | + +### File + +The file can be configured as below, where an explicit file path is required: + + + +```bash +$ k6 run --log-output=file=./k6.log script.js +``` + + + +A valid file path is the unique mandatory field, the other optional fields listed below: + +| key | description | default value | +| --- | ----------- | ------------- | +| level | the minimal level of a message to write out of (in ascending order): trace, debug, info, warning, error, fatal, panic | trace | + +## LogFormat + +A value specifying the log format. By default, k6 includes extra debug information like date and log level. The other options available are: + +- `json`: print all the debug information in JSON format. + +- `raw`: print only the log message. + +| Env | CLI | Code / Config file | Default | +| -------------- | ------------------- | ------------------ | ------- | +| `K6_LOG_FORMAT` | `--log-format`, `-f` | N/A | | + + + +```bash +$ k6 run --log-format raw test.js +``` + + + +## Max redirects + +The maximum number of HTTP redirects that k6 will follow before giving up on a request and +erroring out. Available in both the `k6 run` and the `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| ------------------ | ----------------- | ------------------ | ------- | +| `K6_MAX_REDIRECTS` | `--max-redirects` | `maxRedirects` | `10` | + + + +```javascript +export const options = { + maxRedirects: 10, +}; +``` + + + +## Minimum iteration duration + +Specifies the minimum duration of every single execution (i.e. iteration) of the `default` +function. Any iterations that are shorter than this value will cause that VU to sleep for +the remainder of the time until the specified minimum duration is reached. + +| Env | CLI | Code / Config file | Default | +| --------------------------- | -------------------------- | ---------------------- | -------------- | +| `K6_MIN_ITERATION_DURATION` | `--min-iteration-duration` | `minIterationDuration` | `0` (disabled) | + + + +```javascript +export const options = { + minIterationDuration: '10s', +}; +``` + + + +## No color + +A boolean specifying whether colored output is disabled. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | ------------ | ------------------- | ------- | +| N/A | `--no-color` | N/A | `false` | + + + + +```bash +$ k6 run --no-color script.js +``` + + + +## No connection reuse + +A boolean, true or false, specifying whether k6 should disable keep-alive connections. +Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| ------------------------ | ----------------------- | ------------------- | ------- | +| `K6_NO_CONNECTION_REUSE` | `--no-connection-reuse` | `noConnectionReuse` | `false` | + + + +```javascript +export const options = { + noConnectionReuse: true, +}; +``` + + + +## No cookies reset + +This disables the default behavior of resetting the cookie jar after each VU iteration. If +it's enabled, saved cookies will be persisted across VU iterations. + +| Env | CLI | Code / Config file | Default | +| --------------------- | --- | ------------------ | ------- | +| `K6_NO_COOKIES_RESET` | N/A | `noCookiesReset` | `false` | + + + +```javascript +export const options = { + noCookiesReset: true, +}; +``` + + + +## No summary + +Disables [end-of-test summary](/results-output/end-of-test) generation, +including calls to [`handleSummary()`](/results-output/end-of-test/custom-summary) and `--summary-export`. + +Available in the `k6 run` command. + +| Env | CLI | Code / Config file | Default | +| ------------------ | ----------------- | ------------------ | ------- | +| `K6_NO_SUMMARY` | `--no-summary` | N/A | `false` | + + + +```bash +$ k6 run --no-summary ~/script.js +``` + + + +## No setup + +A boolean specifying whether `setup()` function should be run. Available in `k6 cloud` and `k6 run` commands. + +| Env | CLI | Code / Config file | Default | +| ------------------ | ----------------- | ------------------ | ------- | +| `K6_NO_SETUP` | `--no-setup` | N/A | `false` | + + + +```bash +$ k6 run --no-setup script.js +``` + + + +## No teardown + +A boolean specifying whether `teardown()` function should be run. Available in `k6 cloud` and `k6 run` commands. + +| Env | CLI | Code / Config file | Default | +| ------------------ | ----------------- | ------------------ | ------- | +| `K6_NO_TEARDOWN` | `--no-teardown` | N/A | `false` | + + + +```bash +$ k6 run --no-teardown script.js +``` + + + +## No thresholds + +Disables threshold execution. Available in the `k6 run` command. + +| Env | CLI | Code / Config file | Default | +| ------------------ | ----------------- | ------------------ | ------- | +| `K6_NO_THRESHOLDS` | `--no-thresholds` | N/A | `false` | + + + +```bash +$ k6 run --no-thresholds ~/script.js +``` + + + +## No usage report + +A boolean, true or false. By default, k6 sends a usage report each time it is run, so that we can +track how often people use it. If this option is set to true, no usage report will be made. To +learn more, have a look at the [Usage reports](/misc/usage-collection) documentation. Available in +`k6 run` commands. + +| Env | CLI | Config file | Default | +| -------------------- | ------------------- | ------------------ | ------- | +| `K6_NO_USAGE_REPORT` | `--no-usage-report` | `noUsageReport`\* | `false` | + + + +```bash +$ k6 run --no-usage-report ~/script.js +``` + + + +\* Note that this option is not supported in the exported script options, but can be specified in a configuration file. + + +## No VU connection reuse + +A boolean, true or false, specifying whether k6 should reuse TCP connections between iterations +of a VU. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --------------------------- | -------------------------- | --------------------- | ------- | +| `K6_NO_VU_CONNECTION_REUSE` | `--no-vu-connection-reuse` | `noVUConnectionReuse` | `false` | + + + +```javascript +export const options = { + noVUConnectionReuse: true, +}; +``` + + + +## Paused + +A boolean, true or false, specifying whether the test should start in a paused state. To resume +a paused state you'd use the `k6 resume` command. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| ----------- | ---------------- | ------------------ | ------- | +| `K6_PAUSED` | `--paused`, `-p` | `paused` | `false` | + + + +```javascript +export const options = { + paused: true, +}; +``` + + + +## Quiet + +A boolean, true or false, that disables the progress update bar on the console output. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | ---------------- | ------------------ | ------- | +| N/A | `--quiet`, `-q` | N/A | `false` | + + + +```bash +$ k6 run script.js -d 20s --quiet +``` + + + +## Results output + +Specify the results output. +For information on all available outputs and how to configure them, +refer to [Results output](/results-output/overview/). + +| Env | CLI | Code / Config file | Default | +| --- | ------------- | ------------------ | ------- | +| `K6_OUT` | `--out`, `-o` | N/A | `null` | + + + +```bash +$ k6 run --out influxdb=http://localhost:8086/k6 script.js +``` + + + +## RPS + +The maximum number of requests to make per second, in total across all VUs. Available in `k6 run` and `k6 cloud` commands. + +
+ +**This option is discouraged."" + +The `--rps` option has caveats and is difficult to use correctly. + +For example, in the cloud or distributed execution, this option affects every k6 instance independently. +That is, it is not sharded like VUs are. +We strongly recommend the [arrival-rate executors](/using-k6/scenarios/concepts/open-vs-closed) to simulate constant RPS instead of this option. + +
+ +| Env | CLI | Code / Config file | Default | +| -------- | ------- | ------------------ | --------------- | +| `K6_RPS` | `--rps` | `rps` | `0` (unlimited) | + + + +```javascript +export const options = { + rps: 500, +}; +``` + + + +> ### Considerations when running in the cloud +> +> The option is set per load generator which means that the value you set in the options object of your test script will be multiplied by the number of load generators your test run is using. At the moment we are hosting 300 VUs per load generator instance. In practice that means that if you set the option for 100 rps, and run a test with 1000 VUs, you will spin up 4 load gen instances and effective rps limit of your test run will be 400 + +## Scenarios + +Define one or more execution patterns, with various VU and iteration scheduling +settings, running different exported functions (besides `default`!), using different +environment variables, tags, and more. + +See the [Scenarios](/using-k6/scenarios) article for details and more examples. + +Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | ------- | +| N/A | N/A | `scenarios` | `null` | + + + +```javascript +export const options = { + scenarios: { + my_api_scenario: { + // arbitrary scenario name + executor: 'ramping-vus', + startVUs: 0, + stages: [ + { duration: '5s', target: 100 }, + { duration: '5s', target: 0 }, + ], + gracefulRampDown: '10s', + env: { MYVAR: 'example' }, + tags: { my_tag: 'example' }, + }, + }, +}; +``` + + + +## Setup timeout + +Specify how long the `setup()` function is allow to run before it's terminated and the test fails. + +| Env | CLI | Code / Config file | Default | +| ------------------ | --- | ------------------ | ------- | +| `K6_SETUP_TIMEOUT` | N/A | `setupTimeout` | `"60s"` | + + + +```javascript +export const options = { + setupTimeout: '30s', +}; +``` + + + +## Show logs + +A boolean specifying whether the cloud logs are printed out to the terminal. Available in `k6 cloud` command. + +| Env | CLI | Code / Config file | Default | +| --- | ------------- | ------------------ | ------- | +| N/A | `--show-logs` | N/A | `true` | + + + + +```bash +$ k6 cloud --show-logs=false script.js +``` + + + + +## Stages + +A list of VU `{ target: ..., duration: ... }` objects that specify the target number of VUs to +ramp up or down to for a specific period. Available in `k6 run` and `k6 cloud` commands. + +It is a shortcut option for a single [scenario](/using-k6/scenarios) with a [ramping VUs executor](/using-k6/scenarios/executors/ramping-vus). If used together with the [VUs](#vus) option, the `vus` value is used as the `startVUs` option of the executor. + +| Env | CLI | Code / Config file | Default | +| ----------- | ------------------------------------------------------- | ------------------ | ------------------------------ | +| `K6_STAGES` | `--stage :`, `-s :` | `stages` | Based on `vus` and `duration`. | + + + +```javascript +// The following config would have k6 ramping up from 1 to 10 VUs for 3 minutes, +// then staying flat at 10 VUs for 5 minutes, then ramping up from 10 to 35 VUs +// over the next 10 minutes before finally ramping down to 0 VUs for another +// 3 minutes. + +export const options = { + stages: [ + { duration: '3m', target: 10 }, + { duration: '5m', target: 10 }, + { duration: '10m', target: 35 }, + { duration: '3m', target: 0 }, + ], +}; +``` + +```bash +$ k6 run --stage 5s:10,5m:20,10s:5 script.js + +# or... + +$ K6_STAGES="5s:10,5m:20,10s:5" k6 run script.js +``` + +```bash +C:\k6> k6 run --stage 5s:10,5m:20,10s:5 script.js + +# or... + +C:\k6> set "K6_STAGES=5s:10,5m:20,10s:5" && k6 run script.js + +``` + +```bash +C:\k6> k6 run --stage 5s:10,5m:20,10s:5 script.js + +# or... + +C:\k6> $env:K6_STAGES="5s:10,5m:20,10s:5"; k6 run script.js + +``` + + + +## Summary export + +Save the end-of-test summary report to a JSON file that includes data for all test metrics, checks and thresholds. +This is useful to get the aggregated test results in a machine-readable format, for integration with dashboards, external alerts, CI pipelines, etc. + +While this feature is not deprecated yet, [we now discourage it](/results-output/end-of-test#summary-export-to-a-json-file). +For a better, more flexible JSON export, as well as export of the summary data to different formats (e.g. JUnit/XUnit/etc. XML, HTML, .txt) and complete summary customization, use the [`handleSummary()` function](/results-output/end-of-test/custom-summary). + +Available in the `k6 run` command. + +| Env | CLI | Code / Config file | Default | +| ------------------- | ----------------------------- | ------------------ | ------- | +| `K6_SUMMARY_EXPORT` | `--summary-export ` | N/A | `null` | + + + +```bash +$ k6 run --summary-export export.json script.js + +# or... + +$ K6_SUMMARY_EXPORT="export.json" k6 run script.js +``` + +```bash +C:\k6> k6 run --summary-export export.json script.js + +# or... + +C:\k6> set "K6_SUMMARY_EXPORT=export.json" && k6 run script.js + +``` + +```bash +C:\k6> k6 run --summary-export export.json script.js + +# or... + +C:\k6> $env:K6_SUMMARY_EXPORT="export.json"; k6 run script.js + +``` + + + +See an example file on the [Results Output](/get-started/results-output#summary-export) page. + +## Supply environment variables + +Add/override an [environment variable](/using-k6/environment-variables) with `VAR=value`in a k6 script. Available in `k6 run` and `k6 cloud` commands. + +To make the system environment variables available in the k6 script via `__ENV`, use the [`--include-system-env-vars` option](#include-system-env-vars). + +
+ +**The `-e` flag does not configure options.** + +This flag just provides variables to the script, which the script can use or ignore. +For example, `-e K6_ITERATIONS=120` does _not_ configure the script iterations. + +Compare this behavior with `K6_ITERATIONS=120 k6 run script.js`, which _does_ set iterations. + + +
+ + + + +| Env | CLI | Code / Config file | Default | +| --- | ------------- | ------------------ | ------- | +| N/A | `--env`, `-e` | N/A | `null` | + + + +```bash +$ k6 run -e FOO=bar ~/script.js +``` + + + +## System tags + +Specify which [system tags](/using-k6/tags-and-groups#system-tags) will be in the collected +metrics. Some collectors like the `cloud` one may require that certain system tags be used. +You can specify the tags as an array from the JS scripts or as a comma-separated list via the +CLI. Available in `k6 run` and `k6 cloud` commands + +| Env | CLI | Code / Config file | Default | +| ---------------- | --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------ | +| `K6_SYSTEM_TAGS` | `--system-tags` | `systemTags` | `proto`,`subproto`,`status`,`method`,`url`,`name`,`group`,`check`,`error`,`error_code`,`tls_version`,`scenario`,`service`,`expected_response` | + + + +```javascript +export const options = { + systemTags: ['status', 'method', 'url'], +}; +``` + + + +## Summary time unit + +Define which time unit will be used for _all_ time values in the [end-of-test summary](/results-output/end-of-test). Possible values are `s` (seconds), `ms` (milliseconds) and `us` (microseconds). If no value is specified, k6 will use mixed time units, choosing the most appropriate unit for each value. + +| Env | CLI | Code / Config file | Default | +| ---------------------- | --------------------- | ------------------- | ------- | +| `K6_SUMMARY_TIME_UNIT` | `--summary-time-unit` | `summaryTimeUnit` | `null` | + + + + +```javascript +export const options = { + summaryTimeUnit: 'ms', +}; +``` + + + + +## Summary trend stats + +Define which stats for [`Trend` metrics](/javascript-api/k6-metrics/trend) (e.g. response times, group/iteration durations, etc.) will be shown in the [end-of-test summary](/results-output/end-of-test). Possible values include `avg` (average), `med` (median), `min`, `max`, `count`, as well as arbitrary percentile values (e.g. `p(95)`, `p(99)`, `p(99.99)`, etc.). + +For further summary customization and exporting the summary in various formats (e.g. JSON, JUnit/XUnit/etc. XML, HTML, .txt, etc.), use the [`handleSummary()` function](/results-output/end-of-test/custom-summary). + + +| Env | CLI | Code / Config file | Default | +| ------------------------ | ----------------------- | ------------------- | ------------------------------ | +| `K6_SUMMARY_TREND_STATS` | `--summary-trend-stats` | `summaryTrendStats` | `avg,min,med,max,p(90),p(95)` | + + + +```javascript +export const options = { + summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.99)', 'count'], +}; +``` + + + + + +```bash +$ k6 run --summary-trend-stats="avg,min,med,max,p(90),p(99.9),p(99.99),count" ./script.js +``` + + + +## Tags + +Specify tags that should be set test wide across all metrics. If a tag with the same name has +been specified on a request, check or custom metrics it will have precedence over a test wide +tag. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | ------------------ | ------------------ | ------- | +| N/A | `--tag NAME=VALUE` | `tags` | `null` | + + + +```javascript +export const options = { + tags: { + name: 'value', + }, +}; +``` + + + +## Teardown timeout + +Specify how long the `teardown()` function is allowed to run before it's terminated and the test +fails. + +| Env | CLI | Code / Config file | Default | +| --------------------- | --- | ------------------ | ------- | +| `K6_TEARDOWN_TIMEOUT` | N/A | `teardownTimeout` | `"60s"` | + + + +```javascript +export const options = { + teardownTimeout: '30s', +}; +``` + + + +## Thresholds + +A collection of threshold specifications to configure under what condition(s) a test is considered +successful or not, when it has passed or failed, based on metric data. To learn more, have a look +at the [Thresholds](/using-k6/thresholds) documentation. Available in `k6 run` commands. + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | ------- | +| N/A | N/A | `thresholds` | `null` | + + + +```javascript +export const options = { + thresholds: { + 'http_req_duration': ['avg<100', 'p(95)<200'], + 'http_req_connecting{cdnAsset:true}': ['p(95)<100'], + }, +}; +``` + + + +## Throw + +A boolean, true or false, specifying whether k6 should throw exceptions when certain errors occur, or if it should just log them with a warning. Behaviors that currently depend on this option: + - failing to make [HTTP requests](/javascript-api/k6-http/), e.g. due to a network error + - adding invalid values to [custom metrics](/using-k6/metrics/#custom-metrics) + - setting invalid [per-VU metric tags](/javascript-api/k6-execution/#tags) + +Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| ---------- | --------------- | ------------------ | ------- | +| `K6_THROW` | `--throw`, `-w` | `throw` | `false` | + + + +```javascript +export const options = { + throw: true, +}; +``` + + + +## TLS auth + +A list of TLS client certificate configuration objects. `domains` and `password` are optional, but `cert` and `key` are required. + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | ------- | +| N/A | N/A | `tlsAuth` | `null` | + + + +```javascript +export const options = { + tlsAuth: [ + { + domains: ['example.com'], + cert: open('mycert.pem'), + key: open('mycert-key.pem'), + password: 'mycert-passphrase', + }, + ], +}; +``` + + + +## TLS cipher suites + +A list of cipher suites allowed to be used by in SSL/TLS interactions with a server. +For a full listing of available ciphers go [here](https://golang.org/pkg/crypto/tls/#pkg-constants). + +
+ +Due to limitations in the underlying [go implementation](https://github.com/golang/go/issues/29349), changing the ciphers for TLS 1.3 is *not* supported and will do nothing. + +
+ + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | ------------------------- | +| N/A | N/A | `tlsCipherSuites` | `null` (Allow all suites) | + + + +```javascript +export const options = { + tlsCipherSuites: ['TLS_RSA_WITH_RC4_128_SHA', 'TLS_RSA_WITH_AES_128_GCM_SHA256'], +}; +``` + + + +## TLS version + +Either a string representing the only SSL/TLS version allowed to be used in interactions with a +server, or an object specifying the "min" and "max" versions allowed to be used. + +| Env | CLI | Code / Config file | Default | +| --- | --- | ------------------ | --------------------------- | +| N/A | N/A | `tlsVersion` | `null` (Allow all versions) | + + + +```javascript +export const options = { + tlsVersion: 'tls1.2', +}; +``` + + + + + +```javascript +export const options = { + tlsVersion: { + min: 'ssl3.0', + max: 'tls1.2', + }, +}; +``` + + + + + +## Upload Only + +A boolean specifying whether the test should just be uploaded to the cloud, but not run it. Available in `k6 cloud` command. + +This would be useful if you would like to update a given test and run it later. For example, updating test scripts of a scheduled test from the CI pipelines. + +| Env | CLI | Code / Config file | Default | +| --- | ------------- | ------------------ | ------- | +| `K6_CLOUD_UPLOAD_ONLY` | `--upload-only` | N/A | `false` | + + + + +```bash +$ k6 cloud --upload-only script.js +``` + + + + +## User agent + +A string specifying the user-agent string to use in `User-Agent` headers when sending HTTP +requests. +If you pass an empty string, no `User-Agent` header is sent. +Available in `k6 run` and `k6 cloud` commands + +| Env | CLI | Code / Config file | Default | +|-----------------|----------------|--------------------|-----------------------------------------------------------------------| +| `K6_USER_AGENT` | `--user-agent` | `userAgent` | `k6/0.27.0 (https://k6.io/)` (depending on the version you're using)` | + + + +```javascript +export const options = { + userAgent: 'MyK6UserAgentString/1.0', +}; +``` + + + +## Verbose + +A boolean specifying whether verbose logging is enabled. Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| --- | ------------------ | ------------------- | ------- | +| N/A | `--verbose`, `-v` | N/A | `false` | + + + + +```bash +$ k6 run --verbose script.js +``` + + + +## VUs + +An integer value specifying the number of VUs to run concurrently, used together with the [iterations](#iterations) or [duration](#options) options. If you'd like more control look at the [`stages`](#stages) option or [scenarios](/using-k6/scenarios). + +Available in `k6 run` and `k6 cloud` commands. + +| Env | CLI | Code / Config file | Default | +| -------- | ------------- | ------------------ | ------- | +| `K6_VUS` | `--vus`, `-u` | `vus` | `1` | + + + +```javascript +export const options = { + vus: 10, + duration: '1h', +}; +``` + + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/06 Test lifecycle.md b/src/data/markdown/translated-guides/en/02 Using k6/06 Test lifecycle.md index c9c4e79162..c019c9eb39 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/06 Test lifecycle.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/06 Test lifecycle.md @@ -2,7 +2,6 @@ title: 'Test lifecycle' excerpt: 'The four distinct lifecycle stages in a k6 test are "init", "setup", "VU", and "teardown".' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/test-lifecycle/ -redirect: https://grafana.com/docs/k6/latest/using-k6/test-lifecycle/ --- In the lifecycle of a k6 test, diff --git a/src/data/markdown/translated-guides/en/02 Using k6/07 Modules.md b/src/data/markdown/translated-guides/en/02 Using k6/07 Modules.md index d39bd88b2d..f588cf74df 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/07 Modules.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/07 Modules.md @@ -3,7 +3,6 @@ title: 'Modules' excerpt: 'While writing test scripts, it is common to import different modules, or part of modules, for usage throughout the script. In k6, it is possible to import three different kinds of modules.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/modules/ -redirect: https://grafana.com/docs/k6/latest/using-k6/modules/ --- ## Importing modules diff --git a/src/data/markdown/translated-guides/en/02 Using k6/08 Tags and Groups.md b/src/data/markdown/translated-guides/en/02 Using k6/08 Tags and Groups.md index 36d896f80e..af6f08da0d 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/08 Tags and Groups.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/08 Tags and Groups.md @@ -3,7 +3,6 @@ title: 'Tags and Groups' excerpt: 'k6 provides the Tags and Groups APIs to help you during the analysis and easily visualize, sort and filter your test results.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/tags-and-groups/ -redirect: https://grafana.com/docs/k6/latest/using-k6/tags-and-groups/ --- A load test usually targets a service with different subsystems and resources. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/09 Cookies.md b/src/data/markdown/translated-guides/en/02 Using k6/09 Cookies.md index 03472aff6e..ad13733e2e 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/09 Cookies.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/09 Cookies.md @@ -2,7 +2,6 @@ title: 'Cookies' excerpt: 'k6 will transparently manage the receiving, storage and sending of cookies as described above, so that testing of your cookie-based web site or app will just work.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/cookies/ -redirect: https://grafana.com/docs/k6/latest/using-k6/cookies/ --- HTTP Cookies are used by web sites and apps to store pieces of stateful information on user devices. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols.md index 6f8364b666..d10b0399e4 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols.md @@ -2,7 +2,6 @@ title: "Protocols" excerpt: "Out of the box k6 comes with support for a few protocols: HTTP / WebSockets / gRPC / ..." canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/ -redirect: https://grafana.com/docs/k6/latest/using-k6/protocols/ --- Out of the box, k6 supports the following protocols: diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/01 HTTP-2.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/01 HTTP-2.md new file mode 100644 index 0000000000..0142794d44 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/01 HTTP-2.md @@ -0,0 +1,48 @@ +--- +title: 'HTTP/2' +excerpt: 'When you make HTTP requests in k6 it will automatically upgrade the connection to HTTP/2.0 if the server supports it, just like your web browser would.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/http-2/ +--- + +## Overview + +HTTP/2.0 is the latest version of the HTTP protocol. +It improves significantly upon HTTP/1. +Most importantly, it introduces a binary wire protocol with multiplexed streams over a single TCP connection. +This solves a long-standing performance issue with HTTP/1.1: [head-of-line blocking](https://en.wikipedia.org/wiki/Head-of-line_blocking). + +Well, it at least _partially_ solves it. +The TCP congestion control mechanisms can interfere with the intended independent nature of the multiplexed streams in cases of lost/dropped packets and retransmission/reassembly. +The full solution is to run HTTP/2.0 over UDP, as Google implemented with [QUIC](https://en.wikipedia.org/wiki/QUIC). + +## Additional features of HTTP/2.0 + +- Builtin compression of HTTP headers +- Server push +- Pipelining of requests +- Prioritization of requests + +## Load testing HTTP/2 with k6 + +When you make HTTP requests in k6, k6 automatically upgrades the connection to HTTP/2.0 if the server supports it, just like your web browser would. + +To check what protocol was used for a particular request, refer to the `proto` property of the response object. + + + +```javascript +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +export default function () { + const res = http.get('https://test-api.k6.io/'); + check(res, { + 'protocol is HTTP/2': (r) => r.proto === 'HTTP/2.0', + }); + sleep(1); +} +``` + + + +To see the values that the `r.proto` field can have, refer to the documentation for [k6 HTTP](/javascript-api/k6-http/response). diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/02 WebSockets.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/02 WebSockets.md new file mode 100644 index 0000000000..dcb12135b0 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/02 WebSockets.md @@ -0,0 +1,205 @@ +--- +title: 'WebSockets' +excerpt: 'Comparing HTTP based tests to WebSocket ones, there are some differences in the structure and inner workings of k6.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/websockets/ +--- + +## Overview + +[WebSocket](https://en.wikipedia.org/wiki/WebSocket) is a protocol that provides full-duplex communication channels over a single TCP connection. +It is commonly used by single-page apps (SPAs) and mobile apps, to add server-push based functionality, which usually improves performance in polling-based solutions. + +## Load testing WebSockets with k6 + +
+ +#### An extension with much better and standard API exists + +[xk6-websockets](https://github.com/grafana/xk6-websockets) implements [the WebSockets API living standard](https://websockets.spec.whatwg.org/). While the implementation isn't full, it uses a global event loop instead of local one. + +Currently, it's available as an experimental module [`k6/experimental/websockets`](/javascript-api/k6-experimental/websockets/). It is also likely that it will at some point become part of the core of k6. +
+ +Comparing HTTP-based tests to WebSocket ones, you'll find differences in both structure and inner workings. +The primary difference is that instead of continuously looping the main function (`export default function() { ... }`) over and over, each VU is now runs an asynchronous event loop. + +The basic structure of a WebSocket test looks like this: + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const res = ws.connect(url, params, function (socket) { + socket.on('open', () => console.log('connected')); + socket.on('message', (data) => console.log('Message received: ', data)); + socket.on('close', () => console.log('disconnected')); + }); + + check(res, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + + +In this example, the [connect()](/javascript-api/k6-ws/connect) method takes a "run" function as its third parameter. +That function should accept a [Socket](/javascript-api/k6-ws/socket) object as its only parameter. +The run function forms the basis of the asynchronous event loop. + +When the WebSocket connection is created, the run function will be immediately called, all code inside it will be executed (usually code to set up event handlers), and then blocked until the WebSocket connection is closed (by the remote host or by using [socket.close()](/javascript-api/k6-ws/socket/socket-close)). + +## Error handling + +To catch errors happen during the life of a WebSocket connection, attach a handler to the "error" event: + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const res = ws.connect(url, params, function (socket) { + socket.on('open', function open() { + // ... + }); + + socket.on('error', function (e) { + if (e.error() != 'websocket: close sent') { + console.log('An unexpected error occured: ', e.error()); + } + }); + }); + + check(res, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + + +## Timers + +To schedule a recurring action, use the [socket.setInterval](/javascript-api/k6-ws/socket#section-socketsetinterval) to specify a function to call at a particular interval. + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const res = ws.connect(url, params, function (socket) { + socket.on('open', function open() { + console.log('connected'); + + socket.setInterval(function timeout() { + socket.ping(); + console.log('Pinging every 1sec (setInterval test)'); + }, 1000); + }); + + socket.on('ping', () => console.log('PING!')); + socket.on('pong', () => console.log('PONG!')); + socket.on('close', () => console.log('disconnected')); + }); + + check(res, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + + +## Timeouts + +To add a timeout to the WebSocket connection, pass both a handler function and a timeout value (in milliseconds) to the [socket.setTimeout](/javascript-api/k6-ws/socket/socket-settimeout) function. + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const res = ws.connect(url, params, function (socket) { + socket.on('open', () => console.log('connected')); + socket.on('close', () => console.log('disconnected')); + + socket.setTimeout(function () { + console.log('2 seconds passed, closing the socket'); + socket.close(); + }, 2000); + }); + + check(res, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + + +In the preceding example, the timeout will close the WebSocket connection after 2 seconds. + +## Multiple event handlers + +You can attach multiple handler functions to an event: + + + +```javascript +import ws from 'k6/ws'; +import { check } from 'k6'; + +export default function () { + const url = 'ws://echo.websocket.org'; + const params = { tags: { my_tag: 'hello' } }; + + const response = ws.connect(url, params, function (socket) { + socket.on('open', function open() { + console.log('connected'); + socket.send(Date.now()); + + socket.setInterval(function timeout() { + socket.ping(); + console.log('Pinging every 1sec (setInterval test)'); + }, 1000); + }); + + socket.on('ping', () => console.log('PING!')); + socket.on('pong', () => console.log('PONG!')); + socket.on('pong', () => { + // Multiple event handlers on the same event + console.log('OTHER PONG!'); + }); + + socket.on('close', () => console.log('disconnected')); + + socket.on('error', (e) => { + if (e.error() != 'websocket: close sent') { + console.log('An unexpected error occurred: ', e.error()); + } + }); + + socket.setTimeout(function () { + console.log('2 seconds passed, closing the socket'); + socket.close(); + }, 2000); + }); + + check(response, { 'status is 101': (r) => r && r.status === 101 }); +} +``` + + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/03 gRPC.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/03 gRPC.md new file mode 100644 index 0000000000..bbe4407757 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/03 gRPC.md @@ -0,0 +1,19 @@ +--- +title: 'gRPC' +excerpt: 'gRPC is a lightweight open-source RPC framework. Starting with k6 v0.29.0, we support unary gRPC requests.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/grpc/ +--- + +## Overview + +[gRPC](https://grpc.io/) is a lightweight, open-source RPC framework. +It was originally developed by Google, with version 1.0 released in August 2016. +Since then, it's gained much attention and wide adoption. + +Whereas JSON transmits as human-readable text, gRPC is binary. +The binary format makes data transfer faster and more compact. +In the benchmarks we've seen, gRPC has proved much faster than REST, gRPC's more traditional, JSON-based counterpart. +The messages and services used for gRPC are described in `.proto` files, containing definitions for [Protocol Buffers](https://en.wikipedia.org/wiki/Protocol_Buffers) (protobuf). + +k6 also supports unary gRPC requests to the [k6/net/grpc](/javascript-api/k6-net-grpc) built-in module. +For further information, read [our tutorial about performance testing gRPC services](https://k6.io/blog/performance-testing-grpc-services/). diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS.md new file mode 100644 index 0000000000..a8f436ccbd --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS.md @@ -0,0 +1,36 @@ +--- +title: 'SSL/TLS' +excerpt: 'By default and without any special configuration, k6 will connect and talk to servers over TLS. You just need to make sure to specify your request URLs with the https scheme.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/ssl-tls/ +--- + +Transport Layer Security (TLS), the successor of Secure Socket Layer (SSL), is the mechanism through +which encrypted connections can be established between clients and servers on the web and through +which data can flow with integrity intact. + +Simplified, TLS is made possible by using a Public Key Infrastructure (PKI) involving private +cryptographic keys, certificates of ownership (public, signed with private key), and certificate +authorities (CAs, issuing and asserting the validity of issued certificates). + +The entire system depends on the functioning operation of the CAs. +The system trusts that the cryptographic keys that CAs use to sign certificates of ownership to site/domain owners are kept secret. +It also depends on the domain owners' ability to keep their private cryptographic keys secret. + +If they fail to do so, they have to report the leak to the CA that issued the certificate. +After this disclosure, the CA can revoke the certificate and, in doing so, let browsers and other clients know of the changes through +the Online Certificate Status Protocol (OCSP). + +## TLS in k6 + +By default and without any special configuration, k6 connects and talks to servers over TLS. +You just need to make sure that you specify your request URLs with the `https` scheme. + +K6 supports the following TLS functionalities. +Each is worth discussing in more detail: + +- [TLS client certificates](/using-k6/protocols/ssl-tls/ssl-tls-client-certificates) +- [TLS version and ciphers](/using-k6/protocols/ssl-tls/ssl-tls-version-and-ciphers) (restricting as + well as checking what was used for a HTTP request by checking response object properties) +- [Online Certificate Status Protocol (OCSP)](/using-k6/protocols/ssl-tls/online-certificate-status-protocol-ocsp) +- [Response.timings.tls_handshaking](/javascript-api/k6-http/response) + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/Online Certificate Status Protocol -OCSP-.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/Online Certificate Status Protocol -OCSP-.md new file mode 100644 index 0000000000..72e37a7186 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/Online Certificate Status Protocol -OCSP-.md @@ -0,0 +1,78 @@ +--- +title: 'Online Certificate Status Protocol (OCSP)' +excerpt: 'k6 supports OCSP stapling, receiving and parsing a stapled response as part of +the TLS connection setup.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/ssl-tls/online-certificate-status-protocol-ocsp/ +--- + +## What is OCSP? + +The Online Certificate Status Protocol (OCSP) lets web browsers and clients check the status of an issued TLS certificate with a Certificate Authority (CA), ensuring that the certificate has not been revoked. + +It exists different ways to check whether the certificate has been revoked. +Each way places the burden on different parties: + +- The browser/client: talk to the CA (or through a CA–entrusted OCSP responder) with OCSP. One downside + with this approach is that the CA's servers need to be available. + +- The browser vendor: maintain an up-to-date list of certificate revocations by talking to + the CAs (or through a CA–entrusted OCSP responder) and distributing this list to the browsers + running on users' machines. +- The server side: the server handles the interaction with the CA (or through a CA–entrusted OCSP + responder), caching the results of the periodic updates and including a "stapled response" + (referred to as OCSP stapling) in the TLS connection setup with the browser/client. + +## OCSP with k6 + +k6 supports OCSP stapling. +The application can receive and parse a stapled response as part of the TLS connection setup. +The OCSP response information is available in the `ocsp.stapled_response` property of the response object. + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const res = http.get('https://stackoverflow.com'); + check(res, { + 'is OCSP response good': (r) => r.ocsp.status === http.OCSP_STATUS_GOOD, + }); +} +``` + + + +## Properties of an OCSP object + +The OCSP `ocsp` object contains the following properties: + +| Key | Type | Description | +| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `status` | string | the status of the certificate, see possible values below | +| `revocation_reason` | string | the reason for revocation of the certificate (if that is the status), see possible values below | +| `produced_at` | number | number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when this OCSP stapled response was signed by the CA (or CA–entrusted OCSP responder) | +| `this_update` | number | number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when the status being indicated was known to be correct | +| `next_update` | number | number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when this OCSP stapled response will be refreshed with CA (or by CA entrusted OCSP responder) | +| `revoked_at` | number | number of milliseconds elapsed since 1 January 1970 00:00:00 UTC, representing the time when this certificate was revoked (if that is the status) | + +### Possible values for `status`: + +- `http.OCSP_STATUS_GOOD` +- `http.OCSP_STATUS_REVOKED` +- `http.OCSP_STATUS_UNKNOWN` +- `http.OCSP_STATUS_SERVER_FAILED` + +### Possible values for `revocation_reason`: + +- `http.OCSP_REASON_UNSPECIFIED` +- `http.OCSP_REASON_KEY_COMPROMISE` +- `http.OCSP_REASON_CA_COMPROMISE` +- `http.OCSP_REASON_AFFILIATION_CHANGED` +- `http.OCSP_REASON_SUPERSEDED` +- `http.OCSP_REASON_CESSATION_OF_OPERATION` +- `http.OCSP_REASON_CERTIFICATE_HOLD` +- `http.OCSP_REASON_REMOVE_FROM_CRL` +- `http.OCSP_REASON_PRIVILEGE_WITHDRAWN` +- `http.OCSP_REASON_AA_COMPROMISE` diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/SSL-TLS client certificates.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/SSL-TLS client certificates.md new file mode 100644 index 0000000000..8e2e2ecf3a --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/SSL-TLS client certificates.md @@ -0,0 +1,88 @@ +--- +title: 'SSL/TLS client certificates' +excerpt: 'To use client certificates, you specify global that tell k6 how to map a public certificate and private key to the domains they are valid for.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/ssl-tls/ssl-tls-client-certificates/ +--- + +Discussion about TLS certificates is usually about how clients authenticate servers. +However, both TLS and k6 also support the reverse process, in which servers authenticate clients. + +To use client certificates, specify global [configuration options](/using-k6/options) that tell k6 how to map a public certificate and private key to the domains they are valid for. +You can load the certificate and key from local files or embed them as strings in the script. + +## Loading a certificate and a key from local files + +To load a certificate and a key from local files, use the builtin `open(...)` function: + + + +```javascript +import http from 'k6/http'; + +export const options = { + tlsAuth: [ + { + domains: ['example.com'], + cert: open('./mycert.pem'), + key: open('./mycert-key.pem'), + }, + ], +}; + +export default function () { + http.get('https://example.com/'); +} +``` + + + +## Loading certificate and key from embedded strings + +To load the certificate and key from embedded strings, use this snippet. +Note the use of +[template literals](https://developer.mozilla.org/en-US/Web/JavaScript/Reference/Template_literals) for multi-line strings): + +> ### ⚠ These are just example keys +> +> They're not real and were never used anywhere. + + + +```javascript +import http from 'k6/http'; + +const CERT = `-----BEGIN CERTIFICATE----- +MIIFgTCCA2kCAQEwDQYJKoZIhvcNAQEFBQAwgYExCzAJBgNVBAYTAlNFMRcwFQYD +VQQIEw5TdG9ja2hvbG1zIExhbjESMBAGA1UEBxMJU3RvY2tob2xtMRcwFQYDVQQK +... +/n5QrTGhP51P9Q1THzRfn6cNCDwzSTMVEJr40QhuTJQWASe3miuFmZoG5ykmGqVm +fWQRiQyM330s9vTwFy14J2Bxe4px6cyy7rVXvYL2LvfA4L0T7/x1nUULw+Mpqun1 +R3XRJWqGDjBKXr5q8VatdQO1QLgr +-----END CERTIFICATE-----`; + +const KEY = `-----BEGIN RSA PRIVATE KEY----- +KsZVVI1FTX+F959vqu1S02T+R1JM29PkIfJILIXapKQfb0FWrALU5xpipdPYBWp7 +j5iSp06/7H8ms87Uz9BrOA6rytoRSE0/wEe5WkWdBBgLLPpfOSWZsAA5RGCB2n+N +... +Dk+frzKuiErHFN7HOHAQannui4eLsY0ehYMByowgJIUGzIJyXR6O19hVhV7Py66u +X7/Jy01JXn83LuWdpaPAKU+B42BLP0IGXt5CocPms07HOdtJ/wm2zwHTyfjn9vu+ +HO/dQr6a7DhRu2lLI9Sc983NwRqDKICZQQ/+gqWk8BgQZ1yI9O4AYkzywzAEk3py +-----END RSA PRIVATE KEY-----`; + +export const options = { + tlsAuth: [ + { + domains: ['example.com'], + cert: CERT, + key: KEY, + }, + ], +}; + +export default function () { + http.get('https://example.com/'); +} +``` + + + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/SSL-TLS version and ciphers.md b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/SSL-TLS version and ciphers.md new file mode 100644 index 0000000000..922fd9d8e4 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/10 Protocols/04 SSL-TLS/SSL-TLS version and ciphers.md @@ -0,0 +1,136 @@ +--- +title: 'SSL/TLS version and ciphers' +excerpt: 'To support testing specific client configurations, you can set a specific version or range +of versions of SSL/TLS that should be allowed for a connection.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/protocols/ssl-tls/ssl-tls-version-and-ciphers/ +--- + +To support testing specific client configurations, you can specify a version or range of versions of SSL/TLS that are allowed for a connection. +You can as also specify which cipher suites are allowed for that connection. + + +> #### ⚠️ Reg. ciphers and TLS 1.3 +> +> Due to limitations in the underlying [go implementation](https://github.com/golang/go/issues/29349), changing the ciphers for TLS 1.3 is *not* supported and will do nothing. + +## Limiting SSL/TLS version + +To limit the k6 to a specific SSL/TLS version, use a global +[configuration option](/using-k6/options): + + +```javascript +import http from 'k6/http'; + +export const options = { + tlsVersion: http.TLS_1_2, +}; + +export default function () { + http.get('https://badssl.com'); +} +``` + + + +You can also accept a range of SSL/TLS versions: + + + +```javascript +import http from 'k6/http'; + +export const options = { + tlsVersion: { + min: http.SSL_3_0, + max: http.TLS_1_2, + }, +}; + +export default function () { + http.get('https://badssl.com'); +} +``` + + + +## Versions available to choose from + +Here's the list of available SSL/TLS versions that you can choose from, ordered from oldest version to latest. + +- `http.SSL_3_0` +- `http.TLS_1_0` +- `http.TLS_1_1` +- `http.TLS_1_2` +- `http.TLS_1_3` + +## Limiting cipher suites + +To limit the cipher suites that k6 is allowed to use, there's a global +[configuration option](/using-k6/options). +You choose a list of allowed ciphers: + + + +```javascript +import http from 'k6/http'; + +export const options = { + tlsCipherSuites: ['TLS_RSA_WITH_RC4_128_SHA', 'TLS_RSA_WITH_AES_128_GCM_SHA256'], +}; + +export default function () { + http.get('https://badssl.com'); +} +``` + + + +## Checking SSL/TLS version and cipher suite used in requests + +You can also check which SSL/TLS version and ciphers were used. +To do so, look at the `tls_version` and `tls_cipher_suite` response object properties. + + + +```javascript +import http from 'k6/http'; +import { check } from 'k6'; + +export default function () { + const res = http.get('https://sha256.badssl.com'); + check(res, { + 'is TLSv1.2': (r) => r.tls_version === http.TLS_1_2, + 'is sha256 cipher suite': (r) => r.tls_cipher_suite === 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', + }); +} +``` + + + +## Cipher suites available to choose from + +Here's a list of available SSL/TLS cipher suites: + +- `TLS_RSA_WITH_RC4_128_SHA` +- `TLS_RSA_WITH_3DES_EDE_CBC_SHA` +- `TLS_RSA_WITH_AES_128_CBC_SHA` +- `TLS_RSA_WITH_AES_256_CBC_SHA` +- `TLS_RSA_WITH_AES_128_GCM_SHA256` +- `TLS_RSA_WITH_AES_256_GCM_SHA384` +- `TLS_ECDHE_ECDSA_WITH_RC4_128_SHA` +- `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA` +- `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_RC4_128_SHA` +- `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` +- `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` +- `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` +- `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` +- `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` + +> ### ⚠️ Differences depending on k6 build +> +> This list reflects the available cipher suites in the latest official build. +> If you are using a custom-built k6, the available cipher suites will depend on the Go version you compiled it with, see [https://golang.org/pkg/crypto/tls/#pkg-constants](https://golang.org/pkg/crypto/tls/#pkg-constants). diff --git a/src/data/markdown/translated-guides/en/02 Using k6/11 Environment variables.md b/src/data/markdown/translated-guides/en/02 Using k6/11 Environment variables.md index 02eec79aec..471b96c584 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/11 Environment variables.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/11 Environment variables.md @@ -2,7 +2,6 @@ title: 'Environment variables' excerpt: 'You can access any environment variables from your k6 script code and use this to supply your VUs with configuration information.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/environment-variables/ -redirect: https://grafana.com/docs/k6/latest/using-k6/environment-variables/ --- Often, scripts need only minor tweaks to be reusable in different contexts. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/12 Execution context variables.md b/src/data/markdown/translated-guides/en/02 Using k6/12 Execution context variables.md index d83fad592d..d811d4106f 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/12 Execution context variables.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/12 Execution context variables.md @@ -2,7 +2,6 @@ title: 'Execution context variables' excerpt: 'k6/execution module provides the capability to get information about the current test execution state inside the test script' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/execution-context-variables/ -redirect: https://grafana.com/docs/k6/latest/using-k6/execution-context-variables/ --- In some cases, it's really useful to have information about the script's current test-execution state. For example, you might want to - Have different VUs run different test logic diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios.md index c877445a6e..7e8cf1e5b1 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios.md @@ -3,7 +3,6 @@ title: Scenarios excerpt: 'Scenarios allow us to make in-depth configurations to how VUs and iterations are scheduled. This makes it possible to model diverse traffic patterns in load tests.' hideFromSidebar: false canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/ -redirect: https://grafana.com/docs/k6/latest/using-k6/scenarios/ --- Scenarios configure how VUs and iteration schedules in granular detail. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts.md new file mode 100644 index 0000000000..b9b0f64125 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts.md @@ -0,0 +1,19 @@ +--- +title: "Concepts" +excerpt: High-level explanations about how your executor configuration can change the test execution and test results +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/ +--- + +These topics explain the essential concepts of how scenarios and their executors work. + +Different scenario configurations can affect many different aspects of your system, +including the generated load, utilized resources, and emitted metrics. +If you know a bit about how scenarios work, you'll design better tests and interpret test results with more understanding. + +| On this page | Read about | +|----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------| +| [Open and closed models](/using-k6/scenarios/concepts/open-vs-closed/) | Different ways k6 can schedule VUs, their affects on test results, and how k6 implements the open model in its arrival-rate executors | +| [Graceful Stop](/using-k6/scenarios/concepts/graceful-stop) | A configurable period for iterations to finish or ramp down after the test reaches its scheduled duration | +| [Arrival-rate VU allocation](/using-k6/scenarios/concepts/arrival-rate-vu-allocation/) | How k6 allocates VUs in arrival-rate executors | +| [Dropped iterations](/using-k6/scenarios/concepts/dropped-iterations/) | Possible reasons k6 might drop a scheduled iteration | + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/00 Open-vs-closed.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/00 Open-vs-closed.md new file mode 100644 index 0000000000..0101497470 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/00 Open-vs-closed.md @@ -0,0 +1,126 @@ +--- +title: 'Open and closed models' +slug: '/using-k6/scenarios/concepts/open-vs-closed/' +excerpt: 'k6 has two ways to schedule VUs, which can affect test results. k6 implements the open model in its arrival-rate executors.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/open-vs-closed/ +--- + +Different k6 executors have different ways of scheduling VUs. +Some executors use the _closed model_, while the arrival-rate executors use the _open model_. + +In short, in the closed model, VU iterations start only when the last iteration finishes. +In the open model, on the other hand, VUs arrive independently of iteration completion. +Different models suit different test aims. + +## Closed Model + +In a closed model, the execution time of each iteration dictates the +number of iterations executed in your test. +The next iteration doesn't start until the previous one finishes. + +Thus, in a closed model, the start or arrival rate of +new VU iterations is tightly coupled with the iteration duration (that is, time from start +to finish of the VU's `exec` function, by default the `export default function`): + + + +```javascript +import http from 'k6/http'; + +export const options = { + scenarios: { + closed_model: { + executor: 'constant-vus', + vus: 1, + duration: '1m', + }, + }, +}; + +export default function () { + // The following request will take roughly 6s to complete, + // resulting in an iteration duration of 6s. + + // As a result, New VU iterations will start at a rate of 1 per 6s, + // and we can expect to get 10 iterations completed in total for the + // full 1m test duration. + + http.get('https://httpbin.test.k6.io/delay/6'); +} +``` + + + +Running this script would result in something like: + +```bash + +running (1m01.5s), 0/1 VUs, 10 complete and 0 interrupted iterations +closed_model ✓ [======================================] 1 VUs 1m0s + +``` + +### Drawbacks of using the closed model + +When the duration of the VU iteration is tightly coupled to the start of new VU iterations, +the target system's response time can influence the throughput of the test. +Slower response times means longer iterations and a lower arrival rate of new iterations―and vice versa for faster response times. +In some testing literature, this problem is known as _coordinated omission._ + +In other words, when the target system is stressed and starts to respond more +slowly, a closed model load test will wait, resulting in increased +iteration durations and a tapering off of the arrival rate of new VU iterations. + +This effect is not ideal when the goal is to simulate a certain arrival rate of new VUs, +or more generally throughput (e.g. requests per second). + +## Open model + +Compared to the closed model, the open model decouples VU iterations from +the iteration duration. +The response times of the target system no longer +influence the load on the target system. + +To fix this problem of coordination, you can use an open model, +which decouples the start of new VU iterations from the iteration duration. +This reduces the influence of the target system's response time. + +![Arrival rate closed/open models](../../images/Scenarios/arrival-rate-open-closed-model.png) + +k6 implements the open model with two _arrival rate_ executors: +[constant-arrival-rate](/using-k6/scenarios/executors/constant-arrival-rate) and [ramping-arrival-rate](/using-k6/scenarios/executors/ramping-arrival-rate): + + + +```javascript +import http from 'k6/http'; + +export const options = { + scenarios: { + open_model: { + executor: 'constant-arrival-rate', + rate: 1, + timeUnit: '1s', + duration: '1m', + preAllocatedVUs: 20, + }, + }, +}; + +export default function () { + // With the open model arrival rate executor config above, + // new VU iterations will start at a rate of 1 every second, + // and we can thus expect to get 60 iterations completed + // for the full 1m test duration. + http.get('https://httpbin.test.k6.io/delay/6'); +} +``` + + + +Running this script would result in something like: + +```bash +running (1m09.3s), 000/011 VUs, 60 complete and 0 interrupted iterations +open_model ✓ [======================================] 011/011 VUs 1m0s 1 iters/s +``` diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/01 Graceful stop.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/01 Graceful stop.md new file mode 100644 index 0000000000..45638e8e51 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/01 Graceful stop.md @@ -0,0 +1,97 @@ +--- +title: 'Graceful stop' +excerpt: 'This option is available for all executors except externally-controlled and allows the user to specify a duration to wait before forcefully interrupting them.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/graceful-stop/ +--- + +The `gracefulStop` is a period at the end of the test in which k6 lets iterations in progress finish. + +If a test has a set duration or ramp down, its possible that k6 could interrupt iterations in progress. +These interruptions can lead to skewed metrics and unexpected test results. +To deal with this, k6 scenarios have a `gracefulStop`. +For the `ramping-vus` executor, a related option, `gracefulRampDown`, exists to let VUs finish as their number ramps down. + + +## Graceful stop + +The `gracefulStop` option is available for all executors except `externally-controlled`. +It specifies a duration that k6 will wait before forcefully interrupting an iteration. +The default value is `30s`. + +### Graceful stop example + + + +```javascript +import http from 'k6/http'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'constant-vus', + vus: 100, + duration: '10s', + gracefulStop: '3s', + }, + }, +}; + +export default function () { + const delay = Math.floor(Math.random() * 5) + 1; + http.get(`https://httpbin.test.k6.io/delay/${delay}`); +} +``` + + + +Running this script would result in something like: + +```bash +running (13.0s), 000/100 VUs, 349 complete and 23 interrupted iterations +contacts ✓ [======================================] 100 VUs 10s +``` + +Notice that even though the total test duration is 10s, the actual execution time was 13s +because of `gracefulStop`, giving the VUs a 3s additional time to complete iterations in progress. 23 +of the iterations currently in progress did not complete within this window and was therefore interrupted. + +## The `gracefulRampDown` + +In addition to `gracefulStop`, the [ramping-vus](/using-k6/scenarios/executors/ramping-vus) executor also has a `gracefulRampDown`. + +When the target value for a stage is lower than the target for the previous stage, k6 might need to stop some VUs that were started during the previous stages. +The `gracefulRampDown` option controls how long these VUs have to finish currently before k6 interrupts them. + +To get an idea of how `gracefulRampDown` works, you can run the following script with +`k6 run --verbose`. +In this script, the iteration `sleep` time exceeds the `gracefulRampdown` time. +So, as k6 ramps down to reach the target of the second stage, it must forcibly interrupt VUs. +The `--verbose` flag will log to your console when VUs start, enter the grace period, and are forcibly interrupted. + +```javascript +import http from "k6/http"; +import { sleep } from "k6"; + +export const options = { + discardresponsebodies: true, + scenarios: { + contacts: { + executor: "ramping-vus", + startvus: 0, + stages: [ + { duration: "10s", target: 10 }, + { duration: "10s", target: 0 }, + ], + gracefulRampDown: "1s", + }, + }, +}; + +export default function () { + http.get("https://test.k6.io/contacts.php"); + // adding sleep beyond so that iterations are longer than rampdown + sleep(5); +} +``` + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/02 Arrival-rate VU allocation.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/02 Arrival-rate VU allocation.md new file mode 100644 index 0000000000..0b588efd19 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/02 Arrival-rate VU allocation.md @@ -0,0 +1,123 @@ +--- +title: Arrival-rate VU allocation +excerpt: How k6 allocates VUs in the open-model, arrival-rate executors +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/arrival-rate-vu-allocation/ +--- + +In arrival-rate executors, as long as k6 has VUs available, it starts iterations according to your target rate. +The ability to set iteration rate comes with a bit more configuration complexity: you must pre-allocate a sufficient number of VUs. +In other words, before the tests runs, you must both: + +- Configure load (as new iterations per unit of time) +- Ensure that you've allocated enough VUs. + +Read on to learn about how k6 allocates VUs in the arrival-rate executors. + +
+ +In cloud tests, **`preAllocatedVUs` count against your subscription.** + +When planning a test, consider doing a trial initialization on a local machine to ensure you're allocating VUs efficiently. + +
+ +## Pre-allocation in arrival-rate executors + +As [open-model](/using-k6/scenarios/concepts/open-vs-closed/#open-model) scenarios, arrival-rate executors start iterations according to a configured rate. +For example, you can configure arrival-rate executors to start 10 iterations each second, or minute, or hour. +This behavior is opposed to the closed-model scenarios, in which VUs wait for one iteration to finish before starting another + +Each iteration needs a VU to run it. +Because k6 VUs are single threaded, like other JavaScript runtimes, a VU can only run a single iteration (and its event loop) at a time. +To ensure you have enough, you must pre-allocate a sufficient number. + +In your arrival-rate configuration, three properties determine the iteration rate: + +- k6 starts `rate` number of iterations evenly across the `timeUnit` (default 1s). +- `preAllocatedVUs` sets the number of VUs to initialize to meet the target iteration rate. + +For example, with a `constant-arrival-rate` executor and `rate: 10`, k6 tries to start a new iteration every 100 milliseconds. If the scenario has `rate: 10, timeUnit: '1m'`, k6 tries to start a new iteration every 6 seconds. +Whether it _can_ start the target iteration rate depends on whether the number of allocated VUs is sufficient. + +```javascript +export const options = { + scenarios: { + constant_load: { + executor: "constant-arrival-rate", + preAllocatedVUs: 10, + rate: 10, + timeUnit: "1m", + }, + }, +}; +``` + +In practice, determining the right number of VUs to be able to reach the target iteration rate might take some trial and error, +as the necessary VUs entirely depends on what your iteration code looks like and how quickly the system under test can process requests. + + +## How k6 uses allocated VUs + +Before an arrival-rate scenario starts, k6 first initializes the number of `preAllocatedVUs`. +When the test runs, +the number of available `preAllocatedVUs` determines how many iterations k6 can start. +k6 tries to reach the target iterations per second, +and one of two things can happen: + +| If the executor | Then.. | +|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------| +| Has enough VUs | the extra VUs are "idle," ready to be used when needed. | +| Has insufficient VUs. | k6 emits a [`dropped_iterations` metric](/using-k6/scenarios/concepts/dropped-iterations) for each iteration that it can't run. | + +## Iteration duration affects the necessary allocation + +The necessary allocation depends on the iteration duration: +longer durations need more VUs. + +In a perfect world, you could estimate the number of pre-allocated VUs with this formula: + +``` +preAllocatedVUs = [median_iteration_duration * rate] + constant_for_variance +``` + +In the real world, if you know _exactly_ how long an iteration takes, you likely don't need to run a test. +What's more, as the test goes on, iteration duration likely increases. +If response times slow so much that k6 lacks the VUs to start iterations at the desired rate, +the allocation might be insufficient and k6 will drop iterations. + +To determine your strategy, you can run tests locally and gradually add more pre-allocated VUs. +As dropped iterations can also indicate that the system performance is degrading, this early experimentation can provide useful data on its own. + +## You probably don't need `maxVUs` + +
+ +In cloud tests, the number of `maxVUs` counts against your subscription, +**overriding the number set by `preAllocatedVUs`**. + +
+ +The arrival-rate executors also have a `maxVUs` property. +If you set it, k6 runs in this sequence: + +1. Pre-allocate the `preAllocatedVUs`. +1. Run the test, trying to reach the target iteration rate. +1. If the target exceeds the available VUs, allocate another VU. +1. If the target still exceeds available VUs, continue allocating VUs until reaching the number set by `maxVUs`. + +Though it seems convenient, you should avoid using `maxVUs` in most cases. +Allocating VUs has CPU and memory costs, and allocating VUs as the test runs **can overload the load generator and skew results**. +In Cloud tests, the number of `maxVUs` count against your subscription. +This is because k6 must allocate sufficient resources for `maxVUs` to be initialized, even if they never are. +In almost all cases, the best thing to do is to pre-allocate the number of VUs you need beforehand. + +Some of the times it might make sense to use `maxVUs` include: + +- To determine necessary allocation in first-time tests +- To add a little "cushion" to the pre-allocated VUs that you expect the test needs +- In huge, highly distributed tests, in which you need to carefully scale load generators as you increment VUs. + +## You can't guarantee which VU runs an iteration + +As with all executors, you can't predict the specific VU that an arrival-rate executor uses for a specific iteration. +As the test runs on, the executor might use some or all of the allocated VUs, even if it never needs the entire allocated number to reach the iteration rate. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/03 Dropped iterations.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/03 Dropped iterations.md new file mode 100644 index 0000000000..cdc34bd199 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/00 Concepts/03 Dropped iterations.md @@ -0,0 +1,41 @@ +--- +title: Dropped iterations +excerpt: Explanations about how your scenario configuration or SUT performance can lead to dropped iterations +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/dropped-iterations/ +--- + +Sometimes, a scenario can't run the expected number of iterations. +k6 tracks the number of unsent iterations in a counter metric, `dropped_iterations`. +The number of dropped iterations can be valuable data when you debug executors or analyze results. + +Dropped iterations usually happen for one of two reasons: +- The executor configuration is insufficient. +- The SUT can't handle the configured VU arrival rate. + +### Configuration-related iteration drops + +Dropped iterations happen for different reasons in different types of executors. + +With `shared-iterations` and `per-vu-iterations`, iterations drop if the scenario reaches its `maxDuration` before all iterations finish. +To mitigate this, you likely need to increase the value of the duration. + +With `constant-arrival-rate` and `ramping-arrival-rate`, iterations drop if there are no free VUs. +**If it happens at the beginning of the test, you likely just need to allocate more VUs.** +If this happens later in the test, the dropped iterations might happen because SUT performance is degrading and iterations are taking longer to finish. + +### SUT-related iteration drops + +At a certain point of high latency or longer iteration durations, k6 will no longer have free VUs to start iterations with at the configured rate. +As a result, the executor will drop iterations. + +The reasons for these dropped iterations vary: +- The SUT response has become so long that k6 starts dropping scheduled iterations from the queue. +- The SUT iteration duration has become so long that k6 needs to schedule more VUs to reach the target arrival rate, exceeding the number of scheduled iterations. + +As the causes vary, dropped iterations might mean different things. +A few dropped iterations might indicate a quick network error. +Many dropped iterations might indicate that your SUT has completely stopped responding. + +When you design your test, consider what an acceptable rate of dropped iterations is (the _error budget_). +To assert that the SUT responds within this error budget, you can use the `dropped_iterations` metric in a [Threshold](/using-k6/thresholds). + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors.md new file mode 100644 index 0000000000..5c1dcc433f --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors.md @@ -0,0 +1,51 @@ +--- +title: 'Executors' +excerpt: 'Executors control how k6 schedules VUs and iterations. Choose the executor to model traffic you want to model to test your services' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ +--- + +**Executors** control how k6 schedules VUs and iterations. +The executor that you choose depends on the goals of your test and the type of traffic you want to model. + +Define the executor in `executor` key of the scenario object. +The value is the executor name separated by hyphens. + + +```javascript +export const options = { + scenarios: { + arbitrary_scenario_name: { + //Name of executor + executor: 'ramping-vus', + // more configuration here + }, + }, +}; +``` + + +## All executors + +The following table lists all k6 executors and links to their documentation. + +| Name | Value | Description | +| ---------------------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Shared iterations](/using-k6/scenarios/executors/shared-iterations) | `shared-iterations` | A fixed amount of iterations are
shared between a number of VUs. | +| [Per VU iterations](/using-k6/scenarios/executors/per-vu-iterations) | `per-vu-iterations` | Each VU executes an exact number of iterations. | +| [Constant VUs](/using-k6/scenarios/executors/constant-vus) | `constant-vus` | A fixed number of VUs execute as many
iterations as possible for a specified amount of time. | +| [Ramping VUs](/using-k6/scenarios/executors/ramping-vus) | `ramping-vus` | A variable number of VUs execute as many
iterations as possible for a specified amount of time. | +| [Constant Arrival Rate](/using-k6/scenarios/executors/constant-arrival-rate) | `constant-arrival-rate` | A fixed number of iterations are executed
in a specified period of time. | +| [Ramping Arrival Rate](/using-k6/scenarios/executors/ramping-arrival-rate) | `ramping-arrival-rate` | A variable number of iterations are
executed in a specified period of time. | +| [Externally Controlled](/using-k6/scenarios/executors/externally-controlled) | `externally-controlled` | Control and scale execution at runtime
via [k6's REST API](/misc/k6-rest-api) or the [CLI](https://k6.io/blog/how-to-control-a-live-k6-test). | + + +
+ +For any given scenario, you can't guarantee that a specific VU can run a specific iteration. + +With [`SharedArray`](/javascript-api/k6-data/sharedarray/) and [execution context variables](/using-k6/execution-context-variables/), you can map a specific VU to a specific value in your test data. +So the tenth VU could use the tenth item in your array (or the sixth iteration to the sixth item). + +But, you _cannot_ reliably map, for example, the tenth VU to the tenth iteration. + +
diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/01 shared-iterations.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/01 shared-iterations.md new file mode 100644 index 0000000000..08bb885805 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/01 shared-iterations.md @@ -0,0 +1,88 @@ +--- +title: 'Shared iterations' +excerpt: 'A fixed number of iterations are "shared" between a number of VUs, and the test ends once all iterations are executed.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/shared-iterations/ +--- + +The `shared-iterations` executor shares iterations between the number of VUs. +The test ends once k6 executes all iterations. + +For a shortcut to this executor, use the [vus](/using-k6/k6-options/reference#vus) and [iterations](/using-k6/k6-options/reference#iterations) options. + +
+ +Iterations **are not guaranteed to be evenly distributed** with this executor. +VU that executes faster will complete more iterations than slower VUs. + +To guarantee that every VU completes a specific, fixed number of iterations, [use the per-VU iterations executor](/using-k6/scenarios/executors/per-vu-iterations). + +
+ + +## Options + +Besides the [common configuration options](/using-k6/scenarios#options), +this executor has the following options: + +| Option | Type | Description | Default | +| ------------- | ------- | ---------------------------------------------------------------------------------- | ------- | +| vus | integer | Number of VUs to run concurrently. | `1` | +| iterations | integer | Total number of script iterations to execute across all VUs. | `1` | +| maxDuration | string | Maximum scenario duration before it's forcibly stopped (excluding `gracefulStop`). | `"10m"` | + +## When to use + +This executor is suitable when you want a specific number of VUs to complete a fixed +number of total iterations, and the amount of iterations per VU is unimportant. +If the **time to complete** a number of test iterations is your concern, this executor should perform best. + +An example use case is for quick performance tests in the development build cycle. +As developers make changes, they might run the test against the local code to test for performance regressions. +Thus the executor works well with a _shift-left_ policy, where emphasizes testing performance early in the development cycle, when the cost of a fix is lowest. + +## Example + +The following example schedules 200 total iterations shared by 10 VUs with a maximum test duration of 30 seconds. + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'shared-iterations', + vus: 10, + iterations: 200, + maxDuration: '30s', + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); + // Injecting sleep + // Sleep time is 500ms. Total iteration time is sleep + time to finish request. + sleep(0.5); +} +``` + + + +## Observations + +The following graph depicts the performance of the [example](#example) script: + +![Shared Iterations](./images/shared-iterations.png) + +Based upon our test scenario inputs and results: + +* Test is limited to a fixed number of 200 iterations of the `default` function; +* The number of VUs is fixed to 10, and are initialized before the test begins; +* Each _iteration_ of the `default` function is expected to be roughly 515ms, or ~2/s; +* Maximum throughput (highest efficiency) is therefore expected to be ~20 iters/s, `2 iters/s * 10 VUs`; +* The maximum throughput is maintained for a larger portion of the test; +* The distribution of iterations may be skewed: one VU may have performed 50 iterations, another only 10. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/02 per-vu-iterations.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/02 per-vu-iterations.md new file mode 100644 index 0000000000..273f6510b5 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/02 per-vu-iterations.md @@ -0,0 +1,75 @@ +--- +title: 'Per VU iterations' +excerpt: 'Each VU executes an exact number of iterations.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/per-vu-iterations/ +--- + +With the `per-vu-iterations` executor, each VU executes an exact number of iterations. +The total number of completed iterations equals `vus * iterations`. + +## Options + +Besides the [common configuration options](/using-k6/scenarios#options), +this executor has the following options: + +| Option | Type | Description | Default | +| ------------- | ------- | ---------------------------------------------------------------------------------- | ------- | +| vus | integer | Number of VUs to run concurrently. | `1` | +| iterations | integer | Number of `exec` function iterations to be executed by each VU. | `1` | +| maxDuration | string | Maximum scenario duration before it's forcibly stopped (excluding `gracefulStop`). | `"10m"` | + +## When to use + +Use this executor if you need a specific number of VUs to complete the same number of +iterations. This can be useful when you have fixed sets of test data that you want to +partition between VUs. + +## Example + +The following example schedules 10 VUs to execute 20 iterations _each_. +The test runs 200 total iterations and has a maximum duration of 30 seconds. + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'per-vu-iterations', + vus: 10, + iterations: 20, + maxDuration: '30s', + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); + // Injecting sleep + // Sleep time is 500ms. Total iteration time is sleep + time to finish request. + sleep(0.5); +} +``` + + + +## Observations + +The following graph depicts the performance of the [example](#example) script: + +![Per VU Iterations](./images/per-vu-iterations.png) + +Based upon our test scenario inputs and results: + +* The number of VUs is fixed at 10, and are initialized before the test begins; +* Total iterations are fixed at 20 iterations per VU, i.e. 200 iterations, `10 VUs * 20 iters each`; +* Each _iteration_ of the `default` function is expected to be roughly 515ms, or ~2/s; +* Maximum throughput (highest efficiency) is therefore expected to be ~20 iters/s, `2 iters/s * 10 VUs`; +* The maximum throughput is reached, but not maintained; +* Because the distribution of iterations is even among VUs, a _fast_ VU may finish early and be idle for the remainder of the test, thereby lowering _efficiency_; +* Total duration of 9 seconds is slightly longer than [shared iterations](/using-k6/scenarios/executors/shared-iterations) due to lower efficiency; +* Overall test duration lasts as long as the _slowest_ VU takes to complete 20 requests. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/03 constant-vus.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/03 constant-vus.md new file mode 100644 index 0000000000..c78cd83b34 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/03 constant-vus.md @@ -0,0 +1,69 @@ +--- +title: 'Constant VUs' +excerpt: 'A fixed number of VUs execute as many iterations as possible for a specified amount of time.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/constant-vus/ +--- + +With the `constant-vus` executor, a fixed number of VUs execute as many iterations as possible for a specified amount of time. + +For a shortcut to this executor, use the [vus](/using-k6/options#vus) and [duration](/using-k6/options#duration) options. + +## Options + +Besides the [common configuration options](/using-k6/scenarios#options), +this executor has the following options: + +| Option | Type | Description | Default | +| ----------- | ------- | --------------------------------------------------- | ------- | +| duration(required) | string | Total scenario duration (excluding `gracefulStop`). | - | +| vus | integer | Number of VUs to run concurrently. | `1` | + +## When to use + +Use this executor if you need a specific number of VUs to run for a certain amount of time. + +## Example + +This examples schedules 10 VUs to run constantly for a duration 30 seconds. + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'constant-vus', + vus: 10, + duration: '30s', + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); + // Injecting sleep + // Total iteration time is sleep + time to finish request. + sleep(0.5); +} +``` + + + +## Observations + +The following graph depicts the performance of the [example](#example) script: + +![Constant VUs](./images/constant-vus.png) + +Based upon our test scenario inputs and results: + +* The number of VUs is fixed at 10, and are initialized before the test begins; +* Overall test duration is fixed at the configured 30 second duration; +* Each _iteration_ of the `default` function is expected to be roughly 515ms, or ~2/s; +* Maximum throughput (highest efficiency) is therefore expected to be ~20 iters/s, `2 iters/s * 10 VUs`; +* We see that the maximum throughput is reached and maintained for the majority of the test; +* Approximately 600 iterations are therefore performed in total, `30 seconds * 20 iters/s`. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/04 ramping-vus.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/04 ramping-vus.md new file mode 100644 index 0000000000..208f844b20 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/04 ramping-vus.md @@ -0,0 +1,107 @@ +--- +title: 'Ramping VUs' +excerpt: 'A variable number of VUs execute as many iterations as possible for a specified amount of time.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ramping-vus/ +--- + +With the `ramping-vus` executor, a variable number of VUs executes as many iterations as possible for a specified amount of time. + +For a shortcut to this executor, use the [stages](/using-k6/options#stages) option. + +## Options + +Besides the [common configuration options](/using-k6/scenarios#options), +this executor has the following options: + +| Option | Type | Description | Default | +| ------------------ | ------- | ---------------------------------------------------------------------------------------------- | ------- | +| stages(required) | array | Array of objects that specify the target number of VUs to ramp up or down to. | `[]` | +| startVUs | integer | Number of VUs to run at test start. | `1` | +| gracefulRampDown | string | Time to wait for an already started iteration to finish before stopping it during a ramp down. | `"30s"` | + +## When to use + +This executor is a good fit if you need VUs to ramp up or down during specific periods +of time. + +## Example + +This example schedules a two-stage test, ramping up from 0 to 10 VUs over 20 seconds, then down +to 0 VUs over 10 seconds. + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'ramping-vus', + startVUs: 0, + stages: [ + { duration: '20s', target: 10 }, + { duration: '10s', target: 0 }, + ], + gracefulRampDown: '0s', + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); + // Injecting sleep + // Sleep time is 500ms. Total iteration time is sleep + time to finish request. + sleep(0.5); +} +``` + + + +
+ +With [`gracefulRampDown`](/using-k6/scenarios/concepts/graceful-stop/#the-gracefulrampdown) set to 0 seconds, some iterations might be +interrupted during the ramp down stage. + +
+ +## Observations + +The following graph depicts the performance of the [example](#example) script: + +![Ramping VUs](./images/ramping-vus.png) + +Based upon our test scenario inputs and results: + +* The configuration defines 2 stages for a total test duration of 30 seconds; +* Stage 1 ramps _up_ VUs linearly from the `startVUs` of 0 to the target of 10 over a 20 second duration; +* From the 10 VUs at the end of stage 1, stage 2 then ramps _down_ VUs linearly to the target of 0 over a 10 second duration; +* Each _iteration_ of the `default` function is expected to be roughly 515ms, or ~2/s; +* As the number of VUs changes, the iteration rate directly correlates; each addition of a VU increases the rate by about 2 iters/s, whereas each subtraction of a VU reduces by about 2 iters/s; +* The example performed ~300 iterations over the course of the test. + +## Get the stage index + +To get the current running stage index, use the `getCurrentStageIndex` helper function from the [k6-jslib-utils](/javascript-api/jslib/utils) library. It returns a zero-based number equal to the position in the shortcut `stages` array or in the executor's `stages` array. + +```javascript +import { getCurrentStageIndex } from 'https://jslib.k6.io/k6-utils/1.3.0/index.js'; + +export const options = { + stages: [ + { target: 10, duration: '30s' }, + { target: 50, duration: '1m' }, + { target: 10, duration: '30s' }, + ], +}; + +export default function () { + if (getCurrentStageIndex() === 1) { + console.log('Running the second stage where the expected target is 50'); + } +} +``` + +Using this feature, it is possible to automatically tag using the current running stage. Check the [Tagging stages](/using-k6/tags-and-groups/#tagging-stages) section for more details. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/05 constant-arrival-rate.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/05 constant-arrival-rate.md new file mode 100644 index 0000000000..eb5232eca7 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/05 constant-arrival-rate.md @@ -0,0 +1,105 @@ +--- +title: 'Constant arrival rate' +excerpt: 'A fixed number of iterations are started in a specified period of time.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/constant-arrival-rate/ +--- + +With the `constant-arrival-rate` executor, k6 starts a fixed number of iterations over a specified period of time. +It is an open-model executor, meaning iterations start independently of system response (for details, read +[Open and Closed models](/using-k6/scenarios/concepts/open-vs-closed)). + +This executor continues to start iterations at the given rate as long as VUs are available. +The time to execute an iteration can vary with test logic or the system-under-test response time. +To compensate for this, the executor starts a varied number of VUs to meet the configured iteration rate. +For explanations of how allocation works, read [Arrival-rate VU allocation](/using-k6/scenarios/concepts/arrival-rate-vu-allocation). + +
+ +**Iteration starts are spaced fractionally.** + +Iterations **do not** start at exactly the same time. +At a `rate` of `10` with a `timeUnit` of `1s`, each iteration starts about every tenth of a second (that is, each 100ms). + +
+ +## Options + +Besides the [common configuration options](/using-k6/scenarios#options), +this executor has the following options: + +| Option | Type | Description | Default | +| ------------------ | ------- | --------------------------------------------------------------------------------------- | ------- | +| duration(required) | string | Total scenario duration (excluding `gracefulStop`). | - | +| rate(required) | integer | Number of iterations to start during each `timeUnit` period. | - | +| preAllocatedVUs(required) | integer | Number of VUs to pre-allocate before test start to preserve runtime resources. | - | +| timeUnit | string | Period of time to apply the `rate` value. | `"1s"` | +| maxVUs | integer | Maximum number of VUs to allow during the test run. | If unset, same as `preAllocatedVUs` | + +## When to use + +When you want iterations to remain constant, independent of the performance of the system under test. +This approach is useful for a more accurate representation of RPS, for example. + + +
+ +**Don't put sleep at the end of an iteration.** + +The arrival-rate executors already pace the iteration rate through the `rate` and `timeUnit` properties. +So it's unnecessary to use a `sleep()` function at the end of the VU code. + +
+ +## Example + +This example schedules a constant rate of 30 iterations per second for 30 seconds. +It allocates 50 VUs for k6 to dynamically use as needed. + + + +```javascript +import http from 'k6/http'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'constant-arrival-rate', + + // How long the test lasts + duration: '30s', + + // How many iterations per timeUnit + rate: 30, + + // Start `rate` iterations per second + timeUnit: '1s', + + // Pre-allocate VUs + preAllocatedVUs: 50, + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); +} +``` + + + + +## Observations + +The following graph depicts the performance of the [example](#example) script: + +![Ramping VUs](./images/constant-arrival-rate.png) + +Based upon our test scenario inputs and results: + +* The desired rate of 30 iterations started every 1 second is achieved and maintained for the majority of the test. +* The test scenario runs for the specified 30 second duration. +* Having started with 2 VUs (as specified by the `preAllocatedVUs` option), k6 automatically adjusts the number of VUs to achieve the desired rate, up to the allocated number. For this test, this ended up as 17 VUs. +* Exactly 900 iterations are started in total, `30s * 30 iters/s`. + +> Using too low of a `preAllocatedVUs` setting will reduce the test duration at the desired rate, as resources need to continually be allocated to achieve the rate. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/06 ramping-arrival-rate.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/06 ramping-arrival-rate.md new file mode 100644 index 0000000000..7c2a9026ea --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/06 ramping-arrival-rate.md @@ -0,0 +1,143 @@ +--- +title: 'Ramping arrival rate' +excerpt: 'A variable number of iterations are started in a specified period of time.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ramping-arrival-rate/ +--- + +With the `ramping-arrival-rate` executor, k6 starts iterations at a variable rate. +It is an open-model executor, meaning iterations start independently of system response (for details, read +[Open and Closed models](/using-k6/scenarios/concepts/open-vs-closed)). + +This executor has _stages_ that configure target number of iterations and the time k6 takes to reach or stay at this target. +Unlike the [ramping VUs executor](/using-k6/scenarios/executors/ramping-vus/), which configures VUs, +this executor dynamically changes the number of iterations to start, and starts these iterations as long as the test has enough allocated VUs. +To learn how allocation works, read [Arrival-rate VU allocation](/using-k6/scenarios/concepts/arrival-rate-vu-allocation). + +
+ +**Iteration starts are spaced fractionally.** + +Iterations **do not** start at exactly the same time. +At a `rate` of `10` with a `timeUnit` of `1s`, each iteration starts about every tenth of a second (that is, each 100ms). + +
+ +## Options + +Besides the [common configuration options](/using-k6/scenarios#options), +this executor has the following options: + +| Option | Type | Description | Default | +| ------------------ | ------- | --------------------------------------------------------------------------------------- | ------- | +| stages(required) | array | Array of objects that specify the target number of iterations to ramp up or down to. | `[]` | +| preAllocatedVUs(required) | integer | Number of VUs to pre-allocate before test start to preserve runtime resources. | - | +| startRate | integer | Number of iterations to execute each `timeUnit` period at test start. | `0` | +| timeUnit | string | Period of time to apply the `startRate` to the `stages`' `target` value. Its value is constant for the whole duration of the scenario, it is not possible to change it for a specific stage. | `"1s"` | +| maxVUs | integer | Maximum number of VUs to allow during the test run. | If unset, same as `preAllocatedVUs` | + +## When to use + +If you need start iterations independent of system-under-test performance, and +want to ramp the number of iterations up or down during specific periods of time. + +
+ +**Don't put sleep at the end of an iteration.** + +The arrival-rate executors already pace the iteration rate through the `rate` and `timeUnit` properties. +It's unnecessary to use a `sleep()` function at the end of the VU code. + +
+ +## Example + +This is an example of a four-stage test. + +It starts at the defined `startRate`, 300 iterations per minute over a one minute period. +After one minute, the iteration rate ramps to 600 iterations started per minute over the next two minutes, and stays at this rate for four more minutes. +In the last two minutes, it ramps down to a target of 60 iterations per minute. + + + +```javascript +import http from 'k6/http'; + +export const options = { + discardResponseBodies: true, + + scenarios: { + contacts: { + executor: 'ramping-arrival-rate', + + // Start iterations per `timeUnit` + startRate: 300, + + // Start `startRate` iterations per minute + timeUnit: '1m', + + // Pre-allocate necessary VUs. + preAllocatedVUs: 50, + + stages: [ + // Start 300 iterations per `timeUnit` for the first minute. + { target: 300, duration: '1m' }, + + // Linearly ramp-up to starting 600 iterations per `timeUnit` over the following two minutes. + { target: 600, duration: '2m' }, + + // Continue starting 600 iterations per `timeUnit` for the following four minutes. + { target: 600, duration: '4m' }, + + // Linearly ramp-down to starting 60 iterations per `timeUnit` over the last two minutes. + { target: 60, duration: '2m' }, + ], + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); +} +``` + + +## Observations + +The following graph depicts the performance of the [example](#example) script: + +![Ramping Arrival Rate](./images/ramping-arrival-rate.png) + +Based upon our test scenario inputs and results: + +* The configuration defines 4 stages for a total test duration of 9 minutes. +* Stage 1 maintains the `startRate` iteration rate at 300 iterations started per minute for 1 minute. +* Stage 2 ramps _up_ the iteration rate linearly from the *stage 1* of 300 iterations started per minute, to the target of 600 iterations started per minute over a 2-minute duration. +* Stage 3 maintains the *stage 2* iteration rate at 600 iterations started per minute over a 4-minute duration. +* Stage 4 ramps _down_ the iteration rate linearly to the target rate of 60 iterations started per minute over the last two minutes duration. +* Changes to the iteration rate are performed by k6, adjusting the number of VUs +* The script waits for a period of time (defined by the `gracefulStop` option) for iterations to finish. It doesn't start new iterations during the `gracefulStop` period. +* Our example performed, 4020 iterations over the course of the test. + +## Get the stage index + +To get the current running stage index, use the `getCurrentStageIndex` helper function from the [k6-jslib-utils](/javascript-api/jslib/utils) library. It returns a zero-based number equal to the position in the shortcut `stages` array or in the executor's `stages` array. + +```javascript +import { getCurrentStageIndex } from 'https://jslib.k6.io/k6-utils/1.3.0/index.js'; + +export const options = { + stages: [ + { target: 10, duration: '30s' }, + { target: 50, duration: '1m' }, + { target: 10, duration: '30s' }, + ], +}; + +export default function () { + if (getCurrentStageIndex() === 1) { + console.log('Running the second stage where the expected target is 50'); + } +} +``` + +Using this feature, it is possible to automatically tag using the current running stage. Check the [Tagging stages](/using-k6/tags-and-groups/#tagging-stages) section for more details. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/07 externally-controlled.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/07 externally-controlled.md new file mode 100644 index 0000000000..d94617a84e --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/07 externally-controlled.md @@ -0,0 +1,66 @@ +--- +title: 'Externally controlled' +excerpt: 'Control and scale execution at runtime via k6 REST API or the CLI.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/externally-controlled/ +--- + +Control and scale execution at runtime via [k6's REST API](/misc/k6-rest-api) or +the [CLI](https://k6.io/blog/how-to-control-a-live-k6-test). + +Previously, the `pause`, `resume`, and `scale` CLI commands were used to globally control +k6 execution. This executor does the same job by providing a better API that can be used to +control k6 execution at runtime. + +Note that, passing arguments to the `scale` CLI command for changing the amount of active or +maximum VUs will only affect the externally controlled executor. + +## Options + +**The `externally-controlled` executor has no graceful stop**. + +Besides that, this executor has all the [common configuration options](/using-k6/scenarios#options), +and these particular ones: + +| Option | Type | Description | Default | +| ----------- | ------- | --------------------------------------------------- | ------- | +| duration(required) | string | Total test duration. | - | +| vus | integer | Number of VUs to run concurrently. | - | +| maxVUs | integer | Maximum number of VUs to allow during the test run. | - | + +## When to use + +If you want to control the number of VUs while the test is running. + +Important: this is the only executor that is not supported in `k6 cloud`, it can only be used +locally with `k6 run`. + +## Example + +In this example, we'll execute a test controllable at runtime, starting with 10 VUs up to +a maximum of 50, and a total duration of 10 minutes. + + + +```javascript +import http from 'k6/http'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'externally-controlled', + vus: 10, + maxVUs: 50, + duration: '10m', + }, + }, +}; + +export default function () { + http.get('https://test.k6.io/contacts.php'); +} +``` + +Once the test has started, it can be externally controlled with the `pause`, `resume`, and `scale` CLI commands. + + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/constant-arrival-rate.png b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/constant-arrival-rate.png new file mode 100644 index 0000000000..1e0813e65a Binary files /dev/null and b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/constant-arrival-rate.png differ diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/constant-vus.png b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/constant-vus.png new file mode 100644 index 0000000000..f8001657d0 Binary files /dev/null and b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/constant-vus.png differ diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/per-vu-iterations.png b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/per-vu-iterations.png new file mode 100644 index 0000000000..489c7e99fc Binary files /dev/null and b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/per-vu-iterations.png differ diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/ramping-arrival-rate.png b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/ramping-arrival-rate.png new file mode 100644 index 0000000000..178283670a Binary files /dev/null and b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/ramping-arrival-rate.png differ diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/ramping-vus.png b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/ramping-vus.png new file mode 100644 index 0000000000..eee5b4faed Binary files /dev/null and b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/ramping-vus.png differ diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/shared-iterations.png b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/shared-iterations.png new file mode 100644 index 0000000000..bb68c31089 Binary files /dev/null and b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/01 Executors/images/shared-iterations.png differ diff --git a/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/02 Advanced Examples.md b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/02 Advanced Examples.md new file mode 100644 index 0000000000..d44edec78b --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/14 Scenarios/02 Advanced Examples.md @@ -0,0 +1,199 @@ +--- +title: 'Advanced Examples' +excerpt: 'Advanced Examples using the k6 Scenario API - Using multiple scenarios, different environment variables and tags per scenario.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/scenarios/advanced-examples/ +--- + +You can use multiple scenarios in one script, and these scenarios can be run in sequence or in parallel. +Some ways that you can combine scenarios include the following: +- Have different start times to sequence workloads +- Add per-scenario tags and environment variables +- Make scenario-specific thresholds. +- Use multiple scenarios to run different test logic, so that VUs don't run only the [`default` function](https://k6.io/docs/using-k6/test-lifecycle/). + + +## Combine scenarios + +With the `startTime` property, you can configure your script to start some scenarios later than others. +To sequence your scenarios, you can combine `startTime` with the duration options specific to the executor. +(this is easiest to do with executors with set durations, like the arrival-rate executors). + +This script has two scenarios, `contacts` and `news`, which run in sequence: +1. At the beginning of the test, k6 starts the `contacts` scenario. 50 VUs try to run as many iterations as possible for 30 seconds. +1. After 30 seconds, k6 starts the `news` scenario. 50 VUs each try to run 100 iterations in one minute. + +Along with `startTime`, `duration`, and `maxDuration`, note the different test logic for each scenario. + + + +```javascript +import http from 'k6/http'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'constant-vus', + exec: 'contacts', + vus: 50, + duration: '30s', + }, + news: { + executor: 'per-vu-iterations', + exec: 'news', + vus: 50, + iterations: 100, + startTime: '30s', + maxDuration: '1m', + }, + }, +}; + +export function contacts() { + http.get('https://test.k6.io/contacts.php', { + tags: { my_custom_tag: 'contacts' }, + }); +} + +export function news() { + http.get('https://test.k6.io/news.php', { tags: { my_custom_tag: 'news' } }); +} +``` + + + +## Use different environment variables and tags per scenario. + +The previous example sets tags on individual HTTP request metrics. +But, you can also set tags per scenario, which applies them to other +[taggable](/using-k6/tags-and-groups#tags) objects as well. + + + +```javascript +import http from 'k6/http'; +import { fail } from 'k6'; + +export const options = { + discardResponseBodies: true, + scenarios: { + contacts: { + executor: 'constant-vus', + exec: 'contacts', + vus: 50, + duration: '30s', + tags: { my_custom_tag: 'contacts' }, + env: { MYVAR: 'contacts' }, + }, + news: { + executor: 'per-vu-iterations', + exec: 'news', + vus: 50, + iterations: 100, + startTime: '30s', + maxDuration: '1m', + tags: { my_custom_tag: 'news' }, + env: { MYVAR: 'news' }, + }, + }, +}; + +export function contacts() { + if (__ENV.MYVAR != 'contacts') fail(); + http.get('https://test.k6.io/contacts.php'); +} + +export function news() { + if (__ENV.MYVAR != 'news') fail(); + http.get('https://test.k6.io/news.php'); +} +``` + + + +
+ +By default, k6 applies a `scenario` tag to all metrics in each scenario, whose value is the scenario name. +You can combine these tags with thresholds, or use them to simplify results filtering. + +To disable scenario tags, use the [`--system-tags` option](/using-k6/options#system-tags). + +
+ +## Run multiple scenario functions, with different thresholds + +You can also set different thresholds for different scenario functions. +To do this: +1. Set scenario-specific tags +1. Set thresholds for these tags. + +This test has 3 scenarios, each with different `exec` functions, tags and environment variables, and thresholds: + + + +```javascript +import http from 'k6/http'; +import { sleep } from 'k6'; + +export const options = { + scenarios: { + my_web_test: { + // some arbitrary scenario name + executor: 'constant-vus', + vus: 50, + duration: '5m', + gracefulStop: '0s', // do not wait for iterations to finish in the end + tags: { test_type: 'website' }, // extra tags for the metrics generated by this scenario + exec: 'webtest', // the function this scenario will execute + }, + my_api_test_1: { + executor: 'constant-arrival-rate', + rate: 90, + timeUnit: '1m', // 90 iterations per minute, i.e. 1.5 RPS + duration: '5m', + preAllocatedVUs: 10, // the size of the VU (i.e. worker) pool for this scenario + tags: { test_type: 'api' }, // different extra metric tags for this scenario + env: { MY_CROC_ID: '1' }, // and we can specify extra environment variables as well! + exec: 'apitest', // this scenario is executing different code than the one above! + }, + my_api_test_2: { + executor: 'ramping-arrival-rate', + startTime: '30s', // the ramping API test starts a little later + startRate: 50, + timeUnit: '1s', // we start at 50 iterations per second + stages: [ + { target: 200, duration: '30s' }, // go from 50 to 200 iters/s in the first 30 seconds + { target: 200, duration: '3m30s' }, // hold at 200 iters/s for 3.5 minutes + { target: 0, duration: '30s' }, // ramp down back to 0 iters/s over the last 30 second + ], + preAllocatedVUs: 50, // how large the initial pool of VUs would be + maxVUs: 100, // if the preAllocatedVUs are not enough, we can initialize more + tags: { test_type: 'api' }, // different extra metric tags for this scenario + env: { MY_CROC_ID: '2' }, // same function, different environment variables + exec: 'apitest', // same function as the scenario above, but with different env vars + }, + }, + discardResponseBodies: true, + thresholds: { + // we can set different thresholds for the different scenarios because + // of the extra metric tags we set! + 'http_req_duration{test_type:api}': ['p(95)<250', 'p(99)<350'], + 'http_req_duration{test_type:website}': ['p(99)<500'], + // we can reference the scenario names as well + 'http_req_duration{scenario:my_api_test_2}': ['p(99)<300'], + }, +}; + +export function webtest() { + http.get('https://test.k6.io/contacts.php'); + sleep(Math.random() * 2); +} + +export function apitest() { + http.get(`https://test-api.k6.io/public/crocodiles/${__ENV.MY_CROC_ID}/`); + // no need for sleep() here, the iteration pacing will be controlled by the + // arrival-rate executors above! +} +``` + + diff --git a/src/data/markdown/translated-guides/en/02 Using k6/17 HTTP debugging.md b/src/data/markdown/translated-guides/en/02 Using k6/17 HTTP debugging.md index d87daa51c3..a304fde4c3 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/17 HTTP debugging.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/17 HTTP debugging.md @@ -2,8 +2,6 @@ title: 'HTTP debugging' excerpt: "Things don't always work as expected. For those cases there is a handy CLI flag, --http-debug, that is good to be aware of." hideFromSidebar: true -canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/http-debugging/ -redirect: https://grafana.com/docs/k6/latest/using-k6/http-debugging/ --- Things don't always work as expected. For those cases, enabling the [--http-debug](/using-k6/k6-options/reference#http-debug) option will log HTTP requests and responses to help you debugging the script. diff --git a/src/data/markdown/translated-guides/en/02 Using k6/19 Javascript Compatibility Mode.md b/src/data/markdown/translated-guides/en/02 Using k6/19 Javascript Compatibility Mode.md index 340e051487..5df66b3d2f 100644 --- a/src/data/markdown/translated-guides/en/02 Using k6/19 Javascript Compatibility Mode.md +++ b/src/data/markdown/translated-guides/en/02 Using k6/19 Javascript Compatibility Mode.md @@ -2,8 +2,6 @@ title: JavaScript Compatibility Mode excerpt: 'k6 supports running test scripts with different ECMAScript compatibility modes using --compatibility-mode' hideFromSidebar: true -canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/javascript-typescript-compatibility-mode/ -redirect: https://grafana.com/docs/k6/latest/using-k6/javascript-typescript-compatibility-mode/ --- You can run test scripts with different ECMAScript compatibility modes with the diff --git a/src/data/markdown/translated-guides/en/02 Using k6/20 Workaround Iteration Duration.md b/src/data/markdown/translated-guides/en/02 Using k6/20 Workaround Iteration Duration.md new file mode 100644 index 0000000000..0b5ef88c02 --- /dev/null +++ b/src/data/markdown/translated-guides/en/02 Using k6/20 Workaround Iteration Duration.md @@ -0,0 +1,64 @@ +--- +title: Workaround to calculate iteration_duration +excerpt: 'A threshold can calculate the value of a metric excluding the results of the setup and teardown functions' +hideFromSidebar: true +--- + +A common requested case is to track the `iteration_duration` metric without including time spent for `setup` and `teardown` functions. +This feature is not yet available but a threshold on `iteration_duration` or any pre-existing metrics can be used as a workaround. + +It's based on the concept of creating thresholds for sub-metrics created by tags for the required scope and setting the criteria that always pass. It works with any enabled tags that already works with threshold, for example: +* `iteration_duration{scenario:default}` generates a sub-metric collecting samples only for the default scenario's iteration. `scenario:default` is used because that's the internal k6 scenario name when we haven't specified `options. `scenarios` explicitly and are just using the execution shortcuts instead. +* `iteration_duration{group:::setup}` or `iteration_duration{group:::teardown}` create sub-metrics collecting the duration only for `setup` and `teardown`. `k6` implicitly creates [groups](/using-k6/tags-and-groups#groups) for `setup` and `teardown`, and `::` is the group separator. +* `http_req_duration{scenario:default}` can be useful as well for isolating executed long-running requests. + + + +```javascript +import { sleep } from 'k6'; +import http from 'k6/http'; + +export const options = { + vus: 1, + iterations: 1, + thresholds: { + 'iteration_duration{scenario:default}': [`max>=0`], + 'iteration_duration{group:::setup}': [`max>=0`], + 'iteration_duration{group:::teardown}': [`max>=0`], + 'http_req_duration{scenario:default}': [`max>=0`], + }, +}; + +export function setup() { + http.get('https://httpbin.test.k6.io/delay/5'); +} + +export default function () { + http.get('http://test.k6.io/?where=default'); + sleep(0.5); +} + +export function teardown() { + http.get('https://httpbin.test.k6.io/delay/3'); + sleep(5); +} +``` + + + +Dedicated sub-metrics have been generated collecting samples only for the scope defined by thresholds: + + + +``` + http_req_duration..............: avg=1.48s min=101.95ms med=148.4ms max=5.22s p(90)=4.21s p(95)=4.71s + { expected_response:true }...: avg=1.48s min=101.95ms med=148.4ms max=5.22s p(90)=4.21s p(95)=4.71s + ✓ { scenario:default }.........: avg=148.4ms min=103.1ms med=148.4ms max=193.7ms p(90)=184.64ms p(95)=189.17ms + + iteration_duration.............: avg=5.51s min=1.61s med=6.13s max=8.81s p(90)=8.27s p(95)=8.54s + ✓ { group:::setup }............: avg=6.13s min=6.13s med=6.13s max=6.13s p(90)=6.13s p(95)=6.13s + ✓ { group:::teardown }.........: avg=8.81s min=8.81s med=8.81s max=8.81s p(90)=8.81s p(95)=8.81s + ✓ { scenario:default }.........: avg=1.61s min=1.61s med=1.61s max=1.61s p(90)=1.61s p(95)=1.61s +``` + + diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/01 Overview.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/01 Overview.md index cdb19b445d..b46082cdd1 100644 --- a/src/data/markdown/translated-guides/en/03 Using k6 browser/01 Overview.md +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/01 Overview.md @@ -4,7 +4,6 @@ heading: 'Browser Module Documentation' head_title: 'Browser Module Documentation' excerpt: 'The browser module brings browser automation and end-to-end testing to k6 while supporting core k6 features. Interact with real browsers and collect frontend metrics as part of your k6 tests.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/ -redirect: https://grafana.com/docs/k6/latest/using-k6-browser/ --- diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/02 Running browser tests.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/02 Running browser tests.md index 19bfe35383..a6899dcfc8 100644 --- a/src/data/markdown/translated-guides/en/03 Using k6 browser/02 Running browser tests.md +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/02 Running browser tests.md @@ -2,7 +2,6 @@ title: 'Running browser tests' excerpt: 'Follow along to learn how to run a browser test, interact with elements on the page, wait for page navigation, write assertions and run both browser-level and protocol-level tests in a single script.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/running-browser-tests/ -redirect: https://grafana.com/docs/k6/latest/using-k6-browser/running-browser-tests/ --- Follow along to learn how to: diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/03 Metrics.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/03 Metrics.md index d9627c3b0d..a20d0b49e1 100644 --- a/src/data/markdown/translated-guides/en/03 Using k6 browser/03 Metrics.md +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/03 Metrics.md @@ -2,7 +2,6 @@ title: 'Browser metrics' excerpt: 'An overview of the different browser performance metrics that the browser module tracks.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/metrics/ -redirect: https://grafana.com/docs/k6/latest/using-k6-browser/metrics/ --- Follow along to learn about: diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/04 Migrating to k6 v0-46.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/04 Migrating to k6 v0-46.md index 11928a7558..d5797b873d 100644 --- a/src/data/markdown/translated-guides/en/03 Using k6 browser/04 Migrating to k6 v0-46.md +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/04 Migrating to k6 v0-46.md @@ -2,8 +2,7 @@ title: 'Migrating to k6 v0.46' excerpt: 'A migration guide to ease the process of transitioning to the new k6 browser module version' slug: '/using-k6-browser/migrating-to-k6-v0-46/' -canonicalUrl: https://grafana.com/docs/k6/v0.47.x/using-k6-browser/migrating-to-k6-v0-46/ -redirect: https://grafana.com/docs/k6/v0.47.x/using-k6-browser/migrating-to-k6-v0-46/ +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-46/ --- This guide outlines the key changes you will need to make when moving your existing k6 browser test scripts to the new [k6 browser module](/javascript-api/k6-experimental/browser/) (bundled with [k6 version 0.46](https://github.com/grafana/k6/releases/tag/v0.46.0)). diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices.md index 77fdf79de4..de53638888 100644 --- a/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices.md +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices.md @@ -2,7 +2,6 @@ title: 'Recommended practices' excerpt: 'A list of different examples and recommended practices when working with the k6 browser module' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/recommended-practices/ -redirect: https://grafana.com/docs/k6/latest/using-k6-browser/recommended-practices/ --- This section presents some examples and recommended practices when working with the `k6 browser` module to leverage browser automation as part of your k6 tests. diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices/01 Page object model pattern.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices/01 Page object model pattern.md new file mode 100644 index 0000000000..60f2d98047 --- /dev/null +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices/01 Page object model pattern.md @@ -0,0 +1,96 @@ +--- +title: 'Page object model' +heading: 'Page object model with k6 browser' +head_title: 'Page object model with k6 browser' +excerpt: 'An example on how to implement page object model design pattern with k6 browser' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/recommended-practices/page-object-model-pattern/ +--- + +When working with large test suites, a popular design pattern to improve your code’s maintainability and readability is the [page object model](https://martinfowler.com/bliki/PageObject.html). + +A page object commonly represents an HTML page or significant elements/components within a page, such as a header or a footer. It is a form of encapsulation that hides the details of the UI structure from other places, such as your test files. Through page object models, any changes you need to make on a specific page or element within a page are constrained into a single place, resulting in ease of maintenance and avoiding code duplication. + +Since k6 browser aims to provide rough compatibility with the Playwright API, you can leverage any existing page objects you have and easily re-use them with your k6 browser tests. + +## Implementation + +Let's take an example of a website with a booking form added to the homepage. Imagine you want to write a test that checks that a user can fill out the booking form successfully. + +To model a page object for the homepage, we've created a page object class called `homepage.js`. Different locators are created inside the constructor so that when the homepage class is instantiated, the page locator elements are ready to be used. + +The `homepage.js` class also contains different methods for: +- Navigating to the homepage +- Submitting the form +- Getting the verification message + +When locators need to be updated or other specific changes related to the homepage are made, you only need to update the `homepage.js` class. + + + +```javascript +import { bookingData } from '../data/booking-data.js' + +export class Homepage { + constructor(page) { + this.page = page + this.nameField = page.locator('[data-testid="ContactName"]') + this.emailField = page.locator('[data-testid="ContactEmail"]') + this.phoneField = page.locator('[data-testid="ContactPhone"]'); + this.subjectField = page.locator('[data-testid="ContactSubject"]'); + this.descField = page.locator('[data-testid="ContactDescription"]'); + this.submitButton = page.locator('#submitContact'); + this.verificationMessage = page.locator('.row.contact h2') + } + + async goto() { + await this.page.goto('https://myexamplewebsite/') + } + + async submitForm() { + const { name, email, phone, subject, description } = bookingData + + this.nameField.type(name) + this.emailField.type(email) + this.phoneField.type(phone) + this.subjectField.type(subject) + this.descField.type(description) + await this.submitButton.click() + } + + getVerificationMessage() { + return this.verificationMessage.innerText() + } +} +``` + + + +You can import the `Homepage` class within your test class and invoke the methods you need. This makes the code easier to understand and enforces the separation between your test and business logic. + + + +```javascript +import { chromium } from 'k6/experimental/browser' +import { expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.0/index.js' + +import { Homepage } from '../pages/homepage.js' +import { bookingData } from '../data/booking-data.js' + +export default async function () { + const browser = chromium.launch() + const page = browser.newPage() + + const { name } = bookingData + + const homepage = new Homepage(page) + await homepage.goto() + await homepage.submitForm() + + expect(homepage.getVerificationMessage()).to.contain(name) + + page.close() + browser.close() +} +``` + + \ No newline at end of file diff --git a/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices/02 Selecting elements.md b/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices/02 Selecting elements.md new file mode 100644 index 0000000000..405db92c76 --- /dev/null +++ b/src/data/markdown/translated-guides/en/03 Using k6 browser/100 Recommended Practices/02 Selecting elements.md @@ -0,0 +1,32 @@ +--- +title: 'Selecting elements' +excerpt: 'A guide on how to select elements with the browser module.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6-browser/recommended-practices/selecting-elements/ +--- + +Selectors are strings that represents a specific DOM element on the page. When writing browser-level tests, it's recommended to use selectors that are robust to avoid test flakiness when the DOM structure changes. + +Currently, the browser module supports the standard **CSS and XPath selectors**. + +
+ +Text-based selectors are currently not supported. This will be supported in future releases. + +
+ +## Recommended practices + +The selectors that you choose should not be tightly coupled to any behaviour or styling changes. If your application is prone to changes frequently, it's recommended to use user-facing attributes or custom data attributes as these are not tightly coupled to the element. + +| Selector | Notes | +|------------------------------------------------|--------------------------------------------------------------------------------------------------------------| +| ✅ `page.locator('[aria-label="Login"]')` | User-facing attributes such as ARIA labels are rarely changed so these are great candidates. | +| ✅ `page.locator('[data-test="login"]')` | Custom data attributes are not tightly coupled to the element. | +| ✅ `page.locator('//button[text()="Submit"]')` | Text selectors are also great as text content rarely changes. While we don't support text-based selectors as of yet, xpath can be used as a workaround. | +| ⚠️ `page.locator('#login-btn')` | Selecting an element via its ID is also recommended if the ID doesn't change. | +| ⚠️ `page.locator('.login-btn')` | Selecting an element via its class name should be kept to a minimum as class names can be duplicated. | +| ❌ `page.locator('button')` | Generic elements are not recommended because this has no context. | +| ❌ `page.locator('/html[1]/body[1]/main[1]` | Absolute paths are not recommended as these are tightly coupled to the DOM structure. | + + + diff --git a/src/data/markdown/translated-guides/en/04 Results output/000-Overview.md b/src/data/markdown/translated-guides/en/04 Results output/000-Overview.md index 05a2a3c9dd..e44e87662b 100644 --- a/src/data/markdown/translated-guides/en/04 Results output/000-Overview.md +++ b/src/data/markdown/translated-guides/en/04 Results output/000-Overview.md @@ -2,7 +2,6 @@ title: Overview excerpt: All the ways you can look at k6 results. While the test runs, after the test runs, on an external platform, as summary statistics. canonicalUrl: https://grafana.com/docs/k6/latest/results-output/ -redirect: https://grafana.com/docs/k6/latest/results-output/ --- k6 emits [metrics](/using-k6/metrics) with timestamps at every point of the test. diff --git a/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test.md b/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test.md index f249b7b56c..8f074a4398 100644 --- a/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test.md +++ b/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test.md @@ -2,7 +2,6 @@ title: End of test excerpt: When a test finishes, k6 prints a summary of results, with aggregated metrics and meta-data about the test. You can customize this, or configure the test to write granular metrics to a file. canonicalUrl: https://grafana.com/docs/k6/latest/results-output/end-of-test/ -redirect: https://grafana.com/docs/k6/latest/results-output/end-of-test/ --- When a test finishes, k6 prints a top-level overview of the aggregated results to `stdout`. diff --git a/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test/150-custom-summary.md b/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test/150-custom-summary.md new file mode 100644 index 0000000000..e790475a69 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/100 End-of-test/150-custom-summary.md @@ -0,0 +1,448 @@ +--- +title: Custom summary +excerpt: With handlesummary(), you can customize every part of your report. Change the content, redirect output, and more. +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/end-of-test/custom-summary/ +--- + +With `handleSummary()`, you can completely customize your end-of-test summary. +In this document, read about: +- How `handleSummary()` works +- How to customize the content and output location of your summary +- The data structure of the summary object + +
+ +However, we plan to support the feature for k6 Cloud tests, too. +[Track progress in this issue](https://github.com/grafana/k6-cloud-feature-requests/issues/24). + +
+ +## About `handleSummary()` + +After your test runs, k6 aggregates your metrics into a JavaScript object. +The `handleSummary()` function takes this object as an argument (called `data` in all examples here). + +You can use `handleSummary()` to create a custom summary or return the default summary object. +To get an idea of what the data looks like, +run this script and open the output file, `summary.json`. + + + +```javascript +import http from 'k6/http'; + +export default function () { + http.get('https://test.k6.io'); +} + +export function handleSummary(data) { + return { + 'summary.json': JSON.stringify(data), //the default data object + }; +} +``` + + + + +Fundamentally, `handleSummary()` is just a function that can access a data object. +As such, you can transform the summary data into any text format: JSON, HTML, console, XML, and so on. +You can pipe your custom summary to [standard output or standard error](https://en.wikipedia.org/wiki/Standard_streams), write it to a file, or send it to a remote server. + + +k6 calls `handleSummary()` at the end of the [test lifecycle](/using-k6/test-lifecycle). + +## Use handleSummary() + +The following sections go over the `handleSummary()` syntax and provide some examples. + +To look up the structure of the summary object, refer to the reference section. + +### Syntax + +k6 expects `handleSummary()` to return a `{key1: value1, key2: value2, ...}` map that represents the summary metrics. + +The keys must be strings. +They determine where k6 displays or saves the content: +- `stdout` for standard output +- `stderr` for standard error, +- any relative or absolute path to a file on the system (this operation overwrites existing files) + +The value of a key can have a type of either `string` or [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer). + +You can return multiple summary outputs in a script. +As an example, this `return` statement sends a report to standard output and writes the `data` object to a JSON file. + + + +``` + return { + 'stdout': textSummary(data, { indent: ' ', enableColors: true }), // Show the text summary to stdout... + 'other/path/to/summary.json': JSON.stringify(data), // and a JSON with all the details... + }; +``` + + + +### Example: extract data properties + +This minimal `handleSummary()` extracts the `median` value for the `iteration_duration` metric and prints it to standard output: + + + +```javascript +import http from 'k6/http'; + +export default function () { + http.get('https://test.k6.io'); +} + +export function handleSummary(data) { + const med_latency = data.metrics.iteration_duration.values.med; + const latency_message = `The median latency was ${med_latency}\n`; + + return { + stdout: latency_message, + }; +} +``` + + + + +### Example: modify default output + +If `handleSummary()` is exported, k6 _does not_ print the default summary. +However, if you want to keep the default output, you could import `textSummary` from the [K6 JS utilities library](https://jslib.k6.io/). +For example, you could write a custom HTML report to a file, and use the `textSummary()` function to print the default report to the console. + +You can also use `textSummary()` to make minor modifications to the default end-of-test summary. +To do so: +1. Modify the `data` object however you want. +1. In your `return` statement, pass the modified object as an argument to the `textSummary()` function. + + +The `textSummary()` function comes with a few options: + +|Option| Description| +|-------|-----------| +|`indent`|How to start the summary indentation| +|`enableColor`| Whether to print the summary in color.| + + +For example, this `handleSummary()` modifies the default summary in the following ways: +- It deletes the `http_req_duration{expected_response:true}` sub-metric. +- It deletes all metrics whose key starts with `iteration`. +- It begins each line with the `→` character. + + + + +```javascript +import http from 'k6/http'; +import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js'; + +export default function () { + http.get('https://test.k6.io'); +} + +export function handleSummary(data) { + delete data.metrics['http_req_duration{expected_response:true}']; + + for (const key in data.metrics) { + if (key.startsWith('iteration')) delete data.metrics[key]; + } + + return { + stdout: textSummary(data, { indent: '→', enableColors: true }), + }; +} +``` + + + +In the collapsible, you can use the tabs to compare default and modified reports. + + + + +To see the output of the preceding script, +select **Modified**. +For compactness, these outputs were limited with the `summaryTrendStats` option. + + + + +``` + data_received..................: 63 kB 42 kB/s + data_sent......................: 830 B 557 B/s + http_req_blocked...............: med=10.39µs count=5 p(99)=451.07ms p(99.99)=469.67ms + http_req_connecting............: med=0s count=5 p(99)=223.97ms p(99.99)=233.21ms + http_req_duration..............: med=202.26ms count=5 p(99)=225.81ms p(99.99)=226.71ms + { expected_response:true }...: med=202.26ms count=5 p(99)=225.81ms p(99.99)=226.71ms + http_req_failed................: 0.00% ✓ 0 ✗ 5 + http_req_receiving.............: med=278.27µs count=5 p(99)=377.64µs p(99.99)=381.29µs + http_req_sending...............: med=47.57µs count=5 p(99)=108.42µs p(99.99)=108.72µs + http_req_tls_handshaking.......: med=0s count=5 p(99)=204.42ms p(99.99)=212.86ms + http_req_waiting...............: med=201.77ms count=5 p(99)=225.6ms p(99.99)=226.5ms + http_reqs......................: 5 3.352646/s + iteration_duration.............: med=204.41ms count=5 p(99)=654.78ms p(99.99)=672.43ms + iterations.....................: 5 3.352646/s + vus............................: 1 min=1 max=1 + vus_max........................: 1 min=1 max=1 +``` + +``` +→ data_received..............: 63 kB 39 kB/s +→ data_sent..................: 830 B 507 B/s +→ http_req_blocked...........: med=10.98µs count=5 p(99)=485.16ms p(99.99)=505.18ms +→ http_req_connecting........: med=0s count=5 p(99)=245.05ms p(99.99)=255.15ms +→ http_req_duration..........: med=208.68ms count=5 p(99)=302.87ms p(99.99)=306.61ms +→ http_req_failed............: 0.00% ✓ 0 ✗ 5 +→ http_req_receiving.........: med=206.12µs count=5 p(99)=341.05µs p(99.99)=344.13µs +→ http_req_sending...........: med=47.8µs count=5 p(99)=166.94µs p(99.99)=170.92µs +→ http_req_tls_handshaking...: med=0s count=5 p(99)=207.2ms p(99.99)=215.74ms +→ http_req_waiting...........: med=208.47ms count=5 p(99)=302.49ms p(99.99)=306.23ms +→ http_reqs..................: 5 3.054928/s +→ vus........................: 1 min=1 max=1 +→ vus_max....................: 1 min=1 max=1 +``` + + + + + + +### Example: make custom file format + +This script imports a helper function to turn the summary into a JUnit XML. +The output is a short XML file that reports whether the test thresholds failed. + + + +```javascript +import http from 'k6/http'; + +// Use example functions to generate data +import { jUnit } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js'; +import k6example from 'https://raw.githubusercontent.com/grafana/k6/master/examples/thresholds_readme_example.js'; + +export default k6example; +export const options = { + vus: 5, + iterations: 10, + thresholds: { + http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms + }, +}; + +export function handleSummary(data) { + console.log('Preparing the end-of-test summary...'); + + return { + 'junit.xml': jUnit(data), // Transform summary and save it as a JUnit XML... + }; +} +``` + + + +Output for a test that crosses a threshold looks something like this: + +```xml + + + + + +``` + +### Example: send data to remote server + +You can also send the generated reports to a remote server (over any protocol that k6 supports). + + + +```javascript +import http from 'k6/http'; + +// use example function to generate data +import k6example from 'https://raw.githubusercontent.com/grafana/k6/master/examples/thresholds_readme_example.js'; +export const options = { vus: 5, iterations: 10 }; + +export function handleSummary(data) { + console.log('Preparing the end-of-test summary...'); + + // Send the results to some remote server or trigger a hook + const resp = http.post('https://httpbin.test.k6.io/anything', JSON.stringify(data)); + if (resp.status != 200) { + console.error('Could not send summary, got status ' + resp.status); + } +} +``` + + + +
+ +The last examples use imported helper functions. +These functions might change, so keep an eye on [jslib.k6.io](https://jslib.k6.io/) for the latest. + +Of course, we always welcome [PRs to the jslib](https://github.com/grafana/jslib.k6.io), too! + +
+ +## Summary data reference + +Summary data includes information about your test run time and all built-in and custom metrics (including checks). + +All metrics are in a top-level `metrics` object. +In this object, each metric has an object whose key is the name of the metric. +For example, if your `handleSummary()` argument is called `data`, +the function can access the object about the `http_req_duration` metric at `data.metrics.http_req_duration`. + +### Metric schema + +The following table describes the schema for the metrics object. +The specific values depend on the [metric type](/using-k6/metrics): + + + +| Property | Description | +|----------------------|--------------------------------------------------------------------------------| +| type | String that gives the metric type | +| contains | String that describes the data | +| values | Object with the summary metric values (properties differ for each metric type) | +| thresholds | Object with info about the thresholds for the metric (if applicable) | +| thresholds.{name} | Name of threshold (object) | +| thresholds.{name}.ok | Whether threshold was crossed (boolean) | + + + +
+ +If you change the default trend metrics with the [`summaryTrendStats`](/using-k6/k6-options/reference/#summary-trend-stats) option, +the keys for the values of the trend will change accordingly. + +
+ +### Example summary JSON + +To see what the summary `data` looks like in your specific test run: +1. Add this to your handleSummary() function: + + ``` + return { 'raw-data.json': JSON.stringify(data)};` + ``` + +1. Inspect the resulting `raw-data.json` file. + +The following is an abridged example of how it might look: + + + +```json +{ + "root_group": { + "path": "", + "groups": [ + // Sub-groups of the root group... + ], + "checks": [ + { + "passes": 10, + "fails": 0, + "name": "check name", + "path": "::check name" + }, + // More checks... + ], + "name": "" + }, + "options": { + // Some of the global options of the k6 test run, + // Currently only summaryTimeUnit and summaryTrendStats + }, + + "state": { + "testRunDurationMs": 30898.965069, + // And information about TTY checkers + }, + + "metrics": { + // A map with metric and sub-metric names as the keys and objects with + // details for the metric. These objects contain the following keys: + // - type: describes the metric type, e.g. counter, rate, gauge, trend + // - contains: what is the type of data, e.g. time, default, data + // - values: the specific metric values, depends on the metric type + // - thresholds: any thresholds defined for the metric or sub-metric + // + "http_reqs": { + "type": "counter", + "contains": "default", + "values": { + "count": 40, + "rate": 19.768856959496336 + } + }, + "vus": { + "type": "gauge", + "contains": "default", + "values": { + "value": 1, + "min": 1, + "max": 5 + } + }, + "http_req_duration": { + "type": "trend", + "contains": "time", + "values": { + // actual keys depend depend on summaryTrendStats + + "avg": 268.31137452500013, + "max": 846.198634, + "p(99.99)": 846.1969478817999, + // ... + }, + "thresholds": { + "p(95)<500": { + "ok": false + } + } + }, + "http_req_duration{staticAsset:yes}": { // sub-metric from threshold + "contains": "time", + "values": { + // actual keys depend on summaryTrendStats + "min": 135.092841, + "avg": 283.67766343333335, + "max": 846.198634, + "p(99.99)": 846.1973802197999, + // ... + }, + "thresholds": { + "p(99)<250": { + "ok": false + } + }, + "type": "trend" + }, + // ... + } +} +``` + + + +## Custom output examples + +These examples are community contributions. +We thank everyone who has shared! + +- [Using the JUnit output with Azure Test Plan](https://medium.com/microsoftazure/load-testing-with-azure-devops-and-k6-839be039b68a) +- [Using the JUnit output with TestRail](https://dev.to/kwidera/introducing-testrail-in-you-k6-tests-eck) +- [handleSummary and custom Slack integration](https://medium.com/geekculture/k6-custom-slack-integration-metrics-are-the-magic-of-tests-527aaf613595) +- [Reporting to Xray](https://docs.getxray.app/display/XRAYCLOUD/Performance+and+load+testing+with+k6) +- [HTML reporter](https://github.com/benc-uk/k6-reporter) diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time.md index b9e7087db9..2399712c40 100644 --- a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time.md +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time.md @@ -2,7 +2,6 @@ title: Real time excerpt: Send your time-series k6 metrics to multiple file formats and services canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/ -redirect: https://grafana.com/docs/k6/latest/results-output/real-time/ --- Besides the [end-of-test summary](/results-output/end-of-test), you can also view metrics as granular data points. diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Amazon CloudWatch.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Amazon CloudWatch.md new file mode 100644 index 0000000000..e09df8e8cb --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Amazon CloudWatch.md @@ -0,0 +1,101 @@ +--- +title: 'Amazon CloudWatch' +excerpt: 'You can send k6 results output to Amazon CloudWatch and later visualize them.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/amazon-cloudwatch/ +--- + +
+ +The built-in StatsD output has been deprecated on k6 v0.47.0. You can continue to use this feature by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd), and this guide has been updated to include instructions for how to use it. + +For more information on the reason behind this change, you can follow [this issue](https://github.com/grafana/k6/issues/2982) in the k6 repository. + +
+ +k6 can send metrics data to [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) through the [CloudWatch Agent](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html) by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd). These metrics can then be visualized in dashboards. + +This guide covers how to: + +- Run the CloudWatch agent +- Run the k6 test +- Visualize k6 metrics in Amazon CloudWatch + +## Before you begin + +To use the StatsD output option, you have to build a k6 binary using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd). For more details, refer to [StatsD](/results-output/real-time/statsd). + +## Run the CloudWatch agent + +We presume that you already have a machine that supports both running k6 and CloudWatch agent, which either runs a flavor of GNU/Linux or Windows. Just go ahead and [download](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/download-cloudwatch-agent-commandline.html) the suitable CloudWatch agent version for your operating system. + +1. Create an [IAM role](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/create-iam-roles-for-cloudwatch-agent.html) to send metrics to CloudWatch via the agent. Then, if you are running on Amazon EC2, just [attach](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/iam-roles-for-amazon-ec2.html#attach-iam-role) the role to your EC2 instance, so that you can send metrics to CloudWatch. Otherwise, if you are running on-premises servers, follow this [guide](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-commandline-fleet.html#install-CloudWatch-Agent-iam_user-first). + +2. Download the CloudWatch Agent package suitable for your operating system. For example, on Debian 10 (Buster), we've used the following link. For other operating systems, please refer to this [guide](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/download-cloudwatch-agent-commandline.html): + + ```bash + $ wget https://s3.amazonaws.com/amazoncloudwatch-agent/debian/amd64/latest/amazon-cloudwatch-agent.deb + ``` + +3. Install the package: + + ```bash + $ sudo dpkg -i amazon-cloudwatch-agent.deb + ``` + +4. Configure the agent to receive data from k6. For this, create a file called "_/opt/aws/amazon-cloudwatch-agent/etc/statsd.json_" and paste the following JSON config object into it. This configuration means that the agent would listen on port number 8125, which is the default port number for k6 and StatsD. The interval for collecting metrics is 5 seconds and we don't aggregate them, since we need the raw data later in CloudWatch. + + ```json + { + "metrics": { + "namespace": "k6", + "metrics_collected": { + "statsd": { + "service_address": ":8125", + "metrics_collection_interval": 5, + "metrics_aggregation_interval": 0 + } + } + } + } + ``` + +5. Run the following command to start the agent: + + ```bash + $ sudo amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/statsd.json + ``` + +6. You can check the status of the agent using the following command: + + ```bash + $ amazon-cloudwatch-agent-ctl -a status + ``` + +## Run the k6 test + +Once the agent is running, you can run your test with: + + + + +```bash +$ K6_STATSD_ENABLE_TAGS=true k6 run --out output-statsd script.js +``` + + + +Make sure you're using the k6 binary you built with the xk6-output-statsd extension. + +You can look at the [StatsD](/results-output/real-time/statsd) output page for configuration options. + +## Visualize k6 metrics in Amazon CloudWatch + +Visualization of the exported metrics to CloudWatch is done by creating a dashboard and selecting desired metrics to be displayed. + +![List of k6 metrics](./images/CloudWatch/cloudwatch-k6-metrics.png) + +Here's an example dashboard we've created to visualize the test results. + +![k6 Dashboard on Amazon CloudWatch](./images/CloudWatch/cloudwatch-k6-dashboard.png) + +The above dashboard is exported as JSON and is available [here](https://github.com/k6io/example-cloudwatch-dashboards). diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Apache Kafka.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Apache Kafka.md new file mode 100755 index 0000000000..fdc62cb90e --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Apache Kafka.md @@ -0,0 +1,77 @@ +--- +title: 'Apache Kafka' +excerpt: 'You can use xk6-output-kafka to send k6 metrics in real-time to Kafka, and, optionally, ingest them from InfluxDB.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/apache-kafka/ +--- + +[Apache Kafka](https://kafka.apache.org) is a stream-processing platform for handling real-time data. Using [xk6-output-kafka extension](https://github.com/grafana/xk6-output-kafka), you can send k6 metrics in real-time to Kafka, and, optionally, ingest them from InfluxDB. + + +## Build the k6 version + + + +## Run the k6 test + +You can configure the broker (or multiple ones), topic and message format directly from the command line parameter like this: + + + +```bash +$ k6 run --out xk6-kafka=brokers=broker_host:8000,topic=k6 +``` + + + +or if you want multiple brokers: + + + +```bash +--out xk6-kafka=brokers={broker1,broker2},topic=k6,format=json +``` + + + +You can also specify the message `format` k6 will use. By default, it will be the same as the JSON output, but you can also use the InfluxDB line protocol for direct "consumption" by InfluxDB: + + + +```bash +--out xk6-kafka=brokers=someBroker,topic=someTopic,format=influxdb +``` + + + +You can even modify some of the `format` settings such as `tagsAsFields`: + + + +```bash +--out xk6-kafka=brokers=someBroker,topic=someTopic,format=influxdb,influxdb.tagsAsFields={url,myCustomTag} +``` + + + +### Options + +Here is the full list of options that can be configured and passed to the extension: + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `K6_KAFKA_BROKERS` | `string` | List of brokers | +| `K6_KAFKA_TOPIC` | `string` | The name of the topic to be sent | +| `K6_KAFKA_AUTH_MECHANISM` | `string` | Authentication mechanism. Default `none`. | +| `K6_KAFKA_SASL_USER` | `string` | Kafka User | +| `K6_KAFKA_SASL_PASSWORD` | `string` | Kafka User Password | +| `K6_KAFKA_SSL` | `boolean` | | +| `K6_KAFKA_VERSION` | `string` | Kafka version. Default the latest | +| `K6_KAFKA_INSECURE_SKIP_TLS_VERIFY`| `boolean` | Whether should ignore TLS verifications | +| `K6_KAFKA_PUSH_INTERVAL` | `string` | Interval of the metrics' aggregation and upload to the endpoint | +| `K6_KAFKA_FORMAT` | `string` | Message format. `json` or `influxdb` | +| `K6_KAFKA_LOG_ERROR` | `boolean` | Boolean indicating to log kafka errors | + +## Read more + +- [xk6-output-kafka extension](https://github.com/grafana/xk6-output-kafka) +- [Integrating k6 with Apache Kafka](https://k6.io/blog/integrating-k6-with-apache-kafka) diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 CSV.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 CSV.md new file mode 100644 index 0000000000..8aa1685b15 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 CSV.md @@ -0,0 +1,83 @@ +--- +title: 'CSV' +excerpt: 'You can also make k6 output detailed statistics in a CSV format by using the --out option.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/csv/ +--- + +You can output granular data points in CSV format. +To do so, use `k6 run` with the `--out` flag. +Pass the path for your CSV file as the flag argument: + + + +```bash +$ k6 run --out csv=test_results.csv script.js +``` + + + +You can also get the results gzipped, like this: + + + +```bash +$ k6 run --out csv=test_results.gz script.js +``` + + + +To inspect the output in real time, you can use a command like `tail -f` on the file you save: + +```bash +$ tail -f test_results.csv +``` + + +## CSV format + +The CSV result file will look something like this: + + + +```plain +metric_name,timestamp,metric_value,check,error,error_code,group,method,name,proto,scenario,status,subproto,tls_version,url,extra_tags +http_reqs,1595325560,1.000000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_duration,1595325560,221.899000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_blocked,1595325560,225.275000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_connecting,1595325560,217.680000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_tls_handshaking,1595325560,0.000000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_sending,1595325560,0.112000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_waiting,1595325560,220.280000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +http_req_receiving,1595325560,1.507000,,,,,GET,http://test.k6.io,HTTP/1.1,default,200,,,http://test.k6.io, +vus,1595325560,1.000000,,,,,,,,,,,,, +vus_max,1595325560,20.000000,,,,,,,,,,,,, +checks,1595325561,1.000000,status is 200,,,,,,,default,,,,, +checks,1595325561,0.000000,response body,,,,,,,default,,,,, +data_sent,1595325561,76.000000,,,,,,,,default,,,,, +data_received,1595325561,11045.000000,,,,,,,,default,,,,, +iteration_duration,1595325561,1449.049580,,,,,,,,default,,,,, +iterations,1595325561,1.000000,,,,,,,,default,,,,, +``` + + + +Each entry in the report represents a metric, `metric_name`, along with its value, `metric_value`, at time, `timestamp`. +If an error happens, then the `error` along with the `error_code` fields will be populated. + + +## CSV options + +k6 provides a few options to help you configure your CSV output: + + +| option | Configures | Possible values | Default | Env. variable | +|-------------------------------|--------------------------------------------------|---------------------------------------------------------------------------|------------|------------------------| +| `saveInterval` | The time intervals at which k6 writes to the CSV | Either a string with time units(`"1m45s"`), or a number of milliseconds | `"1s"` | `K6_CSV_SAVE_INTERVAL` | +| `timeFormat` | The timestamp format | unix, unix_nano, unix_micro, unix_milli, [rfc3339](https://datatracker.ietf.org/doc/html/rfc3339), rfc3339_nano | unix | `K6_CSV_TIME_FORMAT` | +| `fileName` | The file name and path where output is saved | N/A | `file.csv` | `K6_CSV_FILENAME` | + + +## Read more + +- [Metrics](/using-k6/metrics) +- [Error codes](/javascript-api/error-codes) diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Cloud.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Cloud.md new file mode 100755 index 0000000000..aecbf7c2d0 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Cloud.md @@ -0,0 +1,146 @@ +--- +title: 'Cloud' +excerpt: 'When streaming the results to the cloud, the machine - where you execute the k6 CLI command - runs the test and uploads the results to the cloud. Then, you will be able to visualize and analyze the results on the web app in real-time.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/cloud/ +--- + +Besides [running cloud tests](/get-started/running-k6/#execution-modes), you can also run a test locally and stream the results to: +- [Grafana Cloud k6](https://grafana.com/docs/grafana-cloud/k6/get-started/run-cloud-tests-from-the-cli/#run-locally-and-stream-to-the-cloud) +- [k6 Cloud](/cloud) (only available for existing customers) + +When streaming the results to the cloud, the machine - where you execute the k6 CLI command - runs the test and uploads the results to the cloud-based solution. Then, you will be able to visualize and analyze the results on the web app in real-time. + + + +## Streaming results vs. running on cloud servers + +Don't confuse `k6 run --out cloud script.js` (what this page is about) with `k6 +cloud script.js`. + +Fundamentally the difference is the machine that the test runs on: + +- `k6 run --out cloud` runs k6 locally and streams the results to the cloud. +- `k6 cloud`, on the other hand, uploads your script to the cloud solution and runs the test on the cloud infrastructure. In this case you'll only see status updates in your CLI. + +In all cases you'll be able to see your test results at [k6 Cloud](https://app.k6.io) or [Grafana Cloud](https://grafana.com/products/cloud/). + +
+ +Data storage and processing are primary cloud costs, +so `k6 run --out cloud` will consume VUh or test runs from your subscription. + +
+ + +## Instructions + +**1 (Optional) - Log in to the cloud** + +Assuming you have installed k6, the first step is to log in to the cloud service. + +With the `k6 login cloud` command, you can set up your API token on the k6 machine to authenticate against the cloud service. + +Copy your token from [k6 Cloud](https://app.k6.io/account/api-token) or [Grafana Cloud k6](https://grafana.com/docs/grafana-cloud/k6/author-run/tokens-and-cli-authentication/) and pass it as: + + + + +```bash +$ k6 login cloud --token +``` + + + +**2 - Run the tests and upload the results** + +Now, k6 will authenticate you against the cloud service, and you can use the `--out` option to send the k6 results to the cloud as: + + + +```bash +$ k6 run --out cloud script.js +``` + + + +Alternatively, you could skip the `k6 login cloud` command when passing your API token to the `k6 run` command as: + + + +```bash +$ K6_CLOUD_TOKEN= k6 run --out cloud script.js +``` + + + +After running the command, the console shows an URL. Copy this URL and paste it in your browser's address bar to visualize the test results. + + + +```bash +execution: local + output: cloud (https://acmecorp.grafana.net/a/k6-app/runs/123456) + script: script.js +``` + + + +![Grafana Cloud k6 Test Results](./images/Cloud/screenshot-stream-k6-results-to-grafana-cloud-k6.png) + +When you send the results to the k6 Cloud with `k6 run --out`, data will be +continuously streamed to the cloud. While this happens the state of the test run +will be marked as `Running`. A test run that ran its course will be marked +`Finished`. The run state has nothing to do with the test passing any +thresholds, only that the test itself is operating correctly. + +If you deliberately abort your test (e.g. by pressing _Ctrl-C_), your test will +end up as `Aborted by User`. You can still look and analyze the test data you +streamed so far. The test will just have run shorter than originally planned. + +Another possibility would be if you lose network connection with the cloud service +while your test is running. In that case the cloud service will patiently wait for +you to reconnect. In the meanwhile your test's run state will continue to +appear as `Running` on the web app. + +If no reconnection happens, the cloud service will time out after two minutes of no +data, setting the run state to `Timed out`. You can still analyze a timed out +test but you'll of course only have access to as much data as was streamed +before the network issue. + +## Advanced settings + +A few [environment variables](/using-k6/environment-variables) can control how k6 streams results with `-o cloud`. + +When streaming, k6 will collect all data and send it to the cloud in batches. + +| Name | Description | +| ---- | ----------- | +| `K6_CLOUD_METRIC_PUSH_INTERVAL` | How often to send data to the cloud (default `'1s'`). | + +k6 can also _aggregate_ the data it sends to the cloud each batch. This +reduces the amount of data sent to the cloud. Aggregation is disabled by +default. + +When using aggregation, k6 will collect incoming test data into time-buckets. +For each data-type collected in such a bucket, it will figure out the dispersion +(by default the [interquartile range][iqr]) around the median value. +Outlier data—far outside the lower and upper quartiles— is not aggregated, preventing the loss of potentially important testing information. + +| Name | Description | +|---------------------------------------------- |----------------------------------------------------------------------------------------------------------| +| `K6_CLOUD_AGGREGATION_PERIOD` | >0s to activate aggregation (default disabled, `'3s'` is a good example to try) | +| `K6_CLOUD_AGGREGATION_CALC_INTERVAL` | How often new data will be aggregated (default `'3s'`). | +| `K6_CLOUD_AGGREGATION_WAIT_PERIOD` | How long to wait for period samples to accumulate before aggregating them (default `'5s'`). | +| `K6_CLOUD_AGGREGATION_MIN_SAMPLES` | If fewer samples than this arrived in interval, skip aggregation (default `100`). | +| `K6_CLOUD_AGGREGATION_OUTLIER_IQR_RADIUS` | Outlier sampling from median to use for Q1 and Q3 quartiles (fraction) (default `0.25` (i.e. [IQR][iqr])). | +| `K6_CLOUD_AGGREGATION_OUTLIER_IQR_COEF_LOWER` | How many quartiles below the lower quartile are treated as non-aggregatable outliers (default `1.5`) | +| `K6_CLOUD_AGGREGATION_OUTLIER_IQR_COEF_UPPER` | How many quartiles above the upper quartile are treated as non-aggregatable outliers (default `1.3`) | + +> When running a test entirely in the cloud with `k6 cloud`, `k6` will always +> aggregate. For that case the aggregation settings are however set by the +> cloud infrastructure and are not controllable from the CLI. + + +[iqr]: https://en.wikipedia.org/wiki/Interquartile_range diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 DataDog.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 DataDog.md new file mode 100755 index 0000000000..46d3145360 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 DataDog.md @@ -0,0 +1,105 @@ +--- +title: 'Datadog' +excerpt: 'Send k6 output to Datadog to visualize load test results and correlate performance testing metrics in Datadog.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/datadog/ +--- + +
+ +The built-in StatsD output has been deprecated on k6 v0.47.0. You can continue to use this feature by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd), and this guide has been updated to include instructions for how to use it. + +For more information on the reason behind this change, you can follow [this issue](https://github.com/grafana/k6/issues/2982) in the k6 repository. + +
+ +k6 can send metrics to [Datadog](https://www.datadoghq.com/). That allows visualizing and correlating performance testing metrics with other monitored metrics in Datadog. + +This guide covers how to: + +- Run the Datadog Agent +- Run the k6 test +- Visualize in Datadog + +## Before you begin + +To use the StatsD output option, you have to build a k6 binary using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd). For more details, refer to [StatsD](/results-output/real-time/statsd). + +## Run the Datadog Agent + +To get k6 metrics into Datadog, k6 sends metrics through the Datadog Agent, which collects, aggregates, and forwards the metrics to the Datadog platform. + +Run the Datadog Agent service as a Docker container with this command: + + + +```bash +DOCKER_CONTENT_TRUST=1 \ +docker run --rm -d \ + --name datadog \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + -v /proc/:/host/proc/:ro \ + -v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro \ + -e DD_SITE="datadoghq.com" \ + -e DD_API_KEY= \ + -e DD_DOGSTATSD_NON_LOCAL_TRAFFIC=1 \ + -p 8125:8125/udp \ + datadog/agent:latest +``` + + + +Replace `` with your [Datadog API key](https://app.datadoghq.com/account/settings#api). + +If your account is registered with Datadog EU, change the value of `DD_SITE` to `datadoghq.eu`. + +
+For additional information, read the Datadog Docker Agent documentation. +
+ +### DogStatsD + +The Datadog agent includes the [DogStatsD](https://docs.datadoghq.com/developers/dogstatsd/) service to collect and aggregate metrics. DogStatsD implements the [StatsD](https://github.com/etsy/statsd) protocol with some extensions. For example, [DogStatsD tagging](https://docs.datadoghq.com/tagging/) allows to collect k6 metrics with tags to distinguish between requests for different URLs, response statuses, groups, etc. + +The instruction above runs the `DogStatsD` service in a [Docker container](https://docs.datadoghq.com/developers/dogstatsd/?tab=containeragent#agent), but it's also possible to run it either as [Host Agent](https://docs.datadoghq.com/developers/dogstatsd/?tab=hostagent#agent), [Kubernetes](https://docs.datadoghq.com/developers/dogstatsd/?tab=kubernetes#agent), and [Helm](https://docs.datadoghq.com/developers/dogstatsd/?tab=helm#agent). + +## Run the k6 test + +Once the Datadog Agent service is running, run the k6 test and send the metrics to the Agent with: + + + +```bash +$ K6_STATSD_ENABLE_TAGS=true k6 run --out output-statsd script.js +``` + + + +Make sure you're using the k6 binary you built with the xk6-output-statsd extension. + +You can look at the [StatsD](/results-output/real-time/statsd) output page for configuration options. + +## Visualize in Datadog + +While running the test, k6 sends metrics periodically to Datadog. By default, these metrics have `k6.` as the name prefix. + +You can visualize k6 metrics in real-time with the [metrics explorer](https://docs.datadoghq.com/metrics/explorer/), [monitors](https://docs.datadoghq.com/monitors/), or [custom dashboards](https://docs.datadoghq.com/graphing/dashboards/). + +![Datadog visualizing performance testing metrics](./images/DataDog/datadog-performance-testing-metrics.png) + +
+ +To learn more about all the types of k6 metrics, read the [k6 Metrics guide](/using-k6/metrics) + +
+ +The first time Datadog detects the `k6.http_reqs` metric, the k6 integration tile is installed automatically, and the default k6 dashboard is added to your dashboard list. + +![k6 Datadog Dashboard](./images/DataDog/k6-datadog-dashboard.png) + +Optionally, you can install the k6 integration tile following these instructions: + +1. Log in to `Datadog`. +2. From the sidebar menu, choose `Integrations` > `Integrations`. +3. Search for `k6`, then select the `k6` integration. +4. Click on the `Configuration` tab option. +5. Scroll down and click on the `Install integration` button. diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Dynatrace.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Dynatrace.md new file mode 100755 index 0000000000..04bd1863d2 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Dynatrace.md @@ -0,0 +1,59 @@ +--- +title: 'Dynatrace' +excerpt: Send k6 output to Dynatrace to visualize load test results and correlate performance testing metrics in Dynatrace. +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/dynatrace/ +--- + +With the [Dynatrace k6 extension](https://github.com/Dynatrace/xk6-output-dynatrace), +you can send visualize and correlate performance testing metrics with the other metrics that you monitor in Dynatrace. + +## Build the k6 version + + + +## Run the test + +Create a Dynatrace API token to send the data. + +
+The Dynatrace API Token must have the scope name "metrics.ingest" (scope type `API v2`). +
+ +You can use the Dynatrace UI: + +![Dynatrace API token](./images/Dynatrace/dynatrace-api-token.png) + +Or a `curl` command (replace `` and the `Api-Token`): + +```bash +curl -X POST "https://.live.dynatrace.com/api/v2/apiTokens" -H "accept: application/json; charset=utf-8" -H "Content-Type: application/json; charset=utf-8" -d "{\"name\":\"\",\"scopes\":[\"metrics.ingest\"]}" -H "Authorization: Api-Token XXXXXXXX" +``` + +Use the previously built k6 binary and run the test passing the Dynatrace URL and API token as follows: + +```bash +# export dynatrace variables +export K6_DYNATRACE_URL=https://.live.dynatrace.com +export K6_DYNATRACE_APITOKEN= + +# run the test +./k6 run script.js -o output-dynatrace +``` + +Check the metrics in your Dynatrace environment, filtering for `k6`: + +![Dynatrace Test result](./images/Dynatrace/dynatrace-k6-metrics.png) + +![Dynatrace Test result](./images/Dynatrace/dynatrace-k6-test-result.png) + +### Options + +When streaming the k6 results to Dynatrace, you can configure the following Dynatrace options: + +| Name | Value | +| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `K6_DYNATRACE_APITOKEN` | Dynatrace API token to write the metrics. The token must have the scope `metrics.ingest API v2`. | +| `K6_DYNATRACE_FLUSH_PERIOD` | Define how often metrics are sent to Dynatrace. The default value is 1 second. | +| `K6_DYNATRACE_URL` | Dynatrace URL. The default value is `https://dynatrace.live.com`. | +| `K6_DYNATRACE_INSECURE_SKIP_TLS_VERIFY` | If `true`, the HTTP client skips TLS verification on the endpoint. The default value is `true`. | +| `K6_DYNATRACE_HEADER_` | Additional headers to include in the HTTP requests. `K6_DYNATRACE_HEADER_COOL_HEADER="cool value of the header"` | diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Elasticsearch.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Elasticsearch.md new file mode 100755 index 0000000000..85ab4b3bf5 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Elasticsearch.md @@ -0,0 +1,77 @@ +--- +title: 'Elasticsearch' +excerpt: k6 has an output extension to store k6 metrics in Elasticsearch. This document shows you how to configure the k6 Elasticsearch integration. +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/elasticsearch/ +--- + +Using the [Elasticsearch k6 extension](https://github.com/elastic/xk6-output-elasticsearch), you can store k6 metrics in [Elasticsearch](https://github.com/elastic/elasticsearch) and analyze your performance results with Kibana or Grafana. + + +## Build the k6 version + + + +## Run the test + +Check that the Elasticsearch instance to store the k6 metrics is running. + +If you're running on Elasticsearch cloud, use the previous k6 binary and run the test passing the cloud credentials as follows: + +```bash +# export cloud configuration +export K6_ELASTICSEARCH_CLOUD_ID=your-cloud-id-here +export K6_ELASTICSEARCH_USER=your-user-here +export K6_ELASTICSEARCH_PASSWORD=your-password-here + +# run the test +./k6 run script.js -o output-elasticsearch +``` + +k6 runs the test script and sends the metrics in real-time to Elasticsearch. + +You can also send the metrics to a local Elasticsearch cluster: + +```bash +# export local url +export K6_ELASTICSEARCH_URL=http://localhost:9200 + +# run the test +./k6 run script.js -o output-elasticsearch +``` + +
+Security and self-signed certificates for non-cloud clusters are not yet supported. +
+ +You can now connect to Elasticsearch and query the [k6 metrics](/using-k6/metrics/) stored in the `k6-metrics` index. +The following example uses an unsecured local Elasticsearch, version `7.17.9`: + +```bash +curl -XGET 'http://localhost:9200/k6-metrics/_search?pretty' -H 'Content-Type: application/json' -d' +{ + "sort": [ + { + "Time": { + "order": "desc" + } + } + ], + "size": 10 +}' +``` + +Or use [Kibana Discover](https://www.elastic.co/guide/en/kibana/7.17/discover.html): + +![Kibana Discover k6 results](./images/Elasticsearch/kibana-discover-test-result.png) + +### Options + +Here is the full list of options that can be configured and passed to the extension: + +| Name | Value | +| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `K6_ELASTICSEARCH_CLOUD_ID` | Elasticsearch `cloud.id`, which can be found in the Elastic Cloud web console. | +| `K6_ELASTICSEARCH_FLUSH_PERIOD` | Define how often metrics are sent to Elasticsearch. The default value is 1 second. | +| `K6_ELASTICSEARCH_URL` | Elasticsearch URL. | +| `K6_ELASTICSEARCH_USER` | Elasticsearch username. | +| `K6_ELASTICSEARCH_PASSWORD` | Elasticsearch password. | diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Grafana Cloud Prometheus.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Grafana Cloud Prometheus.md new file mode 100644 index 0000000000..868e17a539 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Grafana Cloud Prometheus.md @@ -0,0 +1,95 @@ +--- +title: 'Grafana Cloud Prometheus' +excerpt: > + How to upload the test result metrics to Grafana Cloud using Grafana Cloud Prometheus and the k6 output for Prometheus remote write' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/grafana-cloud-prometheus/ +--- + +
+ +This page includes instructions for running a local test that sends the test results to a Prometheus instance in Grafana Cloud. + +For running and managing cloud tests in Grafana Cloud, check out [Grafana Cloud k6](https://grafana.com/docs/grafana-cloud/k6/). + +
+ + +With Grafana Cloud Prometheus and the [k6 output for Prometheus remote write](/results-output/real-time/prometheus-remote-write), you can send your k6 results output to [Grafana Cloud](https://grafana.com/products/cloud) to visualize your testing results. +With k6 metrics in Grafana, you can correlate k6 metrics with other metrics of your observability stack. + +While this topic uses Grafana Cloud as an example, this approach is compatible with any remote write capable Prometheus installation. + + + +## Set up Grafana Cloud Prometheus + +Before you start, you need the following: +- A Grafana Cloud account ([sign up](https://grafana.com/products/cloud/)). +The free plan includes 10,000 Prometheus series. +- The URL, username, and password of your Grafana Cloud Prometheus instance to configure the integration. + +After you've set up your account, follow these steps: + +1. Log in to `Grafana.com` and visit the [Cloud Portal](https://grafana.com/docs/grafana-cloud/fundamentals/cloud-portal/). +Select the **Details** of your Prometheus service. + + ![Grafana Cloud Portal](./images/GrafanaCloud/grafana_cloud_portal.png) + +1. Copy the URL of the Remote Write Endpoint, along with the Username and Instance ID. + + ![Grafana Cloud Prometheus Configuration](./images/GrafanaCloud/grafana_cloud_prometheus_configuration.png) + +1. In the **Password / API Key** section, create and copy an API key of the `MetricsPublisher` role. This will be used as a password. + +![Create API Key](./images/GrafanaCloud/grafana_cloud_create_api_key_metrics_publisher.png) + +## Run the test + +Now, pass the Username, API key, and Remote Write Endpoint of the Grafana Cloud Prometheus Configuration to the k6 binary: + +```bash +K6_PROMETHEUS_RW_USERNAME=USERNAME \ +K6_PROMETHEUS_RW_PASSWORD=API_KEY \ +K6_PROMETHEUS_RW_SERVER_URL=REMOTE_WRITE_ENDPOINT \ +k6 run -o experimental-prometheus-rw script.js +``` + +## Visualize test results + +To visualize test results with Grafana, you can import the [k6 Prometheus dashboard by Grafana k6](https://grafana.com/grafana/dashboards/19665-k6-prometheus/). + +On the Dashboards UI: + +- Click `New` and select `Import`. +- Paste the Grafana URL or ID of the dashboard, and click `Load`. +- Select the Prometheus data source, and click `Import`. + +![k6 Prometheus Dashboard](./images/Prometheus/k6-prometheus-dashboard-part1.png) + +Optionally, when running the test, you can set the `testid` tag as a [wide test tag](https://k6.io/docs/using-k6/tags-and-groups/#test-wide-tags) to filter results of a particular test run on this dashboard (or in PromQL queries). `testid` can be any unique string that allows you to identify the test run. + + + +```bash +K6_PROMETHEUS_RW_USERNAME=USERNAME \ +K6_PROMETHEUS_RW_PASSWORD=API_KEY \ +K6_PROMETHEUS_RW_SERVER_URL=REMOTE_WRITE_ENDPOINT \ +k6 run -o experimental-prometheus-rw --tag testid=TEST_ID script.js +``` + + + +Additionally, you can also use the [Explore UI](https://grafana.com/docs/grafana/latest/explore/) to query k6 time series, design your visualization panels, and add them to any of your existing dashboards. + +![Explore k6 metrics in Grafana Cloud](./images/GrafanaCloud/grafana_cloud_explore_k6_metrics_from_extension.png) + +All the k6 time series have a **k6_** prefix. +For more details, refer to the documentation on the [mapping of k6 metrics with Prometheus metrics](/results-output/real-time/prometheus-remote-write/#metrics-mapping). + +It's also important to understand the default [Trend metric conversion](/results-output/real-time/prometheus-remote-write/#trend-metric-conversions) process and the format and querying limitations. The [`K6_PROMETHEUS_RW_TREND_STATS` option](/results-output/real-time/prometheus-remote-write/#options) allows you to convert trend metrics to multiple Prometheus time series. For instance, `K6_PROMETHEUS_RW_TREND_STATS=p(95),p(99),max,min` transforms each k6 trend metric into four Prometheus metrics as follows: + +- `k6_*_p95` +- `k6_*_p99` +- `k6_*_max` +- `k6_*_min` + diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 InfluxDB.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 InfluxDB.md new file mode 100644 index 0000000000..9d5d1d4c18 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 InfluxDB.md @@ -0,0 +1,57 @@ +--- +title: 'InfluxDB' +excerpt: 'k6 has an output extension to store k6 metrics in InfluxDB v2. This document shows you how to configure this integration.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/influxdb/ +--- + +Using the [InfluxDB extension](https://github.com/grafana/xk6-output-influxdb), you can store k6 metrics in [InfluxDB v2.0](https://docs.influxdata.com/influxdb/v2.0/) and analyze your performance results with Grafana or [other tools](https://docs.influxdata.com/influxdb/cloud-serverless/query-data/tools/). + +## Build the k6 version + + + +## Run the test + +Check that the InfluxDB instance to store the k6 metrics is running. + +Use the previous k6 binary and run the test passing the following [options](#options): + +```bash +K6_INFLUXDB_ORGANIZATION="" \ +K6_INFLUXDB_BUCKET="" \ +K6_INFLUXDB_TOKEN="" \ +K6_INFLUXDB_ADDR="" \ +./k6 run script.js -o xk6-influxdb +``` + + +k6 runs the test script and sends the [k6 metrics](/using-k6/metrics/) in real-time to the InfluxDB instance. You can now select the bucket to [query](https://docs.influxdata.com/influxdb/v2.7/query-data/) and [visualize](https://docs.influxdata.com/influxdb/v2.7/visualize-data/) the stored k6 metrics, for example, using the [InfluxDB Data Explorer](https://docs.influxdata.com/influxdb/v2.7/query-data/execute-queries/data-explorer/). + +
+ +![InfluxDB Data Explorer / k6 bucket](./images/InfluxDB/influxdb-data-explorer-k6-bucket.png) + + +## Options + +Here is the full list of options that can be configured and passed to the extension: + +| ENV | Default | Description | +|-----|---------|-------------| +| K6_INFLUXDB_ORGANIZATION | | Your InfluxDB organization name. [View organizations](https://docs.influxdata.com/influxdb/v2.7/organizations/). | +| K6_INFLUXDB_BUCKET | | The bucket name to store k6 metrics data. [Manage buckets](https://docs.influxdata.com/influxdb/v2.7/organizations/buckets/). | +| K6_INFLUXDB_TOKEN | | An API token that provides authorized access to store data. [Manage API tokens](https://docs.influxdata.com/influxdb/v2.7/security/tokens/). | +| K6_INFLUXDB_ADDR | http://localhost:8086 | The address of the InfluxDB instance. | +| K6_INFLUXDB_PUSH_INTERVAL | 1s | The flush's frequency of the `k6` metrics. | +| K6_INFLUXDB_CONCURRENT_WRITES | 4 | Number of concurrent requests for flushing data. It is useful when a request takes more than the expected time (more than flush interval). | +| K6_INFLUXDB_TAGS_AS_FIELDS | vu:int,iter:int,url | A comma-separated string to set `k6` metrics as non-indexable fields (instead of tags). An optional type can be specified using :type as in vu:int will make the field integer. The possible field types are int, bool, float and string, which is the default. Example: vu:int,iter:int,url:string,event_time:int. | +| K6_INFLUXDB_INSECURE | false | When `true`, it will skip `https` certificate verification. | +| K6_INFLUXDB_PRECISION | 1ns | The timestamp [Precision](https://docs.influxdata.com/influxdb/v2.7/reference/glossary/#precision). | + +## Grafana Dashboards + +You can use Grafana to query and visualize data from an InfluxDB instance. The instructions are available on [InfluxDB](https://docs.influxdata.com/influxdb/v2.7/tools/grafana/) and [Grafana](https://grafana.com/docs/grafana/latest/datasources/influxdb/). + +You can also build a [custom Grafana dashboard](/results-output/grafana-dashboards/) to visualize the testing results in your own way. + +For testing purposes, the [influxdb extension](https://github.com/grafana/xk6-output-influxdb) repository includes a [docker-compose setup](https://github.com/grafana/xk6-output-influxdb#docker-compose) with two basic dashboards. diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 JSON.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 JSON.md new file mode 100755 index 0000000000..ca1b2f0dca --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 JSON.md @@ -0,0 +1,146 @@ +--- +title: 'JSON' +excerpt: 'You can also make k6 output detailed statistics in JSON format by using the --out option.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/json/ +--- + +You can output granular data points in JSON format. +To do so, use `k6 run` with the `--out` flag. +Pass the path for your JSON file as the flag argument: + + + +```bash +$ k6 run --out json=test_results.json script.js +``` + +```bash +$ docker run -it --rm \ + -v :/scripts \ + -v :/jsonoutput \ + grafana/k6 run --out json=/jsonoutput/my_test_result.json /scripts/script.js + +# Note that the docker user must have permission to write to ! +``` + + + +Or if you want to get the result gzipped, like this: + + + +```bash +$ k6 run --out json=test_results.gz script.js +``` + +```bash +$ docker run -it --rm \ + -v :/scripts \ + -v :/jsonoutput \ + grafana/k6 run --out json=/jsonoutput/my_test_result.gz /scripts/script.js + +# Note that the docker user must have permission to write to ! +``` + + + +To inspect the output in real time, you can use a command like `tail -f` on the file you save: + +```bash +$ tail -f test_results.json +``` + +## JSON format + +The JSON output has lines as follows: + + + +```json +{"type":"Metric","data":{"type":"gauge","contains":"default","tainted":null,"thresholds":[],"submetrics":null},"metric":"vus"} +{"type":"Point","data":{"time":"2017-05-09T14:34:45.625742514+02:00","value":5,"tags":null},"metric":"vus"} +{"type":"Metric","data":{"type":"trend","contains":"time","tainted":null,"thresholds":["avg<1000"],"submetrics":null},"metric":"http_req_duration"} +{"type":"Point","data":{"time":"2017-05-09T14:34:45.239531499+02:00","value":459.865729,"tags":{"group":"::my group::json","method":"GET","status":"200","url":"https://httpbin.test.k6.io/get"}},"metric":"http_req_duration"} +``` + + + +Each line either has information about a metric, or logs a data point (sample) for a metric. +Lines consist of three items: + +- `type` - can have the values [Metric](#metric) or [Point](#point) where `Metric` means the line is declaring a metric, and `Point` is an actual data point (sample) for a metric. +- `data` - is a dictionary that contains lots of stuff, varying depending on the `"type"` above. +- `metric` - the name of the metric. + +### Metric + +This line has metadata about a metric. Here, `"data"` contains the following: + +- `"type"` - the metric type ("gauge", "rate", "counter" or "trend") +- `"contains"` - information on the type of data collected (can e.g. be "time" for timing metrics) +- `"tainted"` - has this metric caused a threshold to fail? +- `"threshold"` - are there any thresholds attached to this metric? +- `"submetrics"` - any derived metrics created as a result of adding a threshold using tags. + +### Point + +This line has actual data samples. Here, `"data"` contains these fields: + +- `"time"` - timestamp when the sample was collected +- `"value"` - the actual data sample; time values are in milliseconds +- `"tags"` - dictionary with tagname-tagvalue pairs that can be used when filtering results data + +## Processing JSON output + +You can use [jq][jq_url] to process the k6 JSON output. + +You can quickly create [filters][jq_filters_url] to return a particular metric of the JSON file: + + + +```bash +$ jq '. | select(.type=="Point" and .metric == "http_req_duration" and .data.tags.status >= "200")' myscript-output.json +``` + + + +And calculate an aggregated value of any metric: + + + +```bash +$ jq '. | select(.type=="Point" and .metric == "http_req_duration" and .data.tags.status >= "200") | .data.value' myscript-output.json | jq -s 'add/length' +``` + + + + + +```bash +$ jq '. | select(.type=="Point" and .metric == "http_req_duration" and .data.tags.status >= "200") | .data.value' myscript-output.json | jq -s min +``` + + + + + +```bash +$ jq '. | select(.type=="Point" and .metric == "http_req_duration" and .data.tags.status >= "200") | .data.value' myscript-output.json | jq -s max +``` + + + +For more advanced cases, check out the [jq Manual][jq_manual_url] + +[jq_url]: https://stedolan.github.io/jq/ 'jq_url' +[jq_filters_url]: https://stedolan.github.io/jq/manual/#Basicfilters 'jq_filters_url' +[jq_manual_url]: https://stedolan.github.io/jq/manual/ 'jq_manual_url' + +## Summary export + +If you want to see only the aggregated data, you can export the end-of-test summary to a JSON file. +For more details, refer to the `handleSummary()` topic in the [end-of-test summary docs](/results-output/end-of-test/). + +## Read more + +- [Metrics](/using-k6/metrics) diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Netdata.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Netdata.md new file mode 100644 index 0000000000..d221bb6ecc --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Netdata.md @@ -0,0 +1,61 @@ +--- +title: 'Netdata' +excerpt: 'You can send k6 output to Netdata. With this integration, visualize test results with zero configuration, in seconds' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/netdata/ +--- + +
+ +The built-in StatsD output has been deprecated on k6 v0.47.0. You can continue to use this feature by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd), and this guide has been updated to include instructions for how to use it. + +For more information on the reason behind this change, you can follow [this issue](https://github.com/grafana/k6/issues/2982) in the k6 repository. + +
+ +k6 can send performance testing metrics to [Netdata](https://netdata.cloud). This enables the user to start monitoring their k6 experiments right away, as Netdata is a monitoring tool with: + +- Auto-configuration and auto-detection of data sources +- Automatic organization of metrics into **meaningful** charts and visualization +- Per-second metric granularity + +## Before you begin + +To use the StatsD output option, you have to build a k6 binary using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd). For more details, refer to [StatsD](/results-output/real-time/statsd). + +## Run Netdata + +Netdata runs on many different systems and platforms. The easiest way to download and run Netdata is through the `kickstart` script: + +```bash +bash <(curl -Ss https://my-netdata.io/kickstart.sh) +``` +Alternatively, you can read more about installing and running Netdata in their [documentation](https://learn.netdata.cloud/docs/get-started/). + +## Setup Netdata for K6 + +Netdata runs a fully functional [StatsD](https://github.com/netdata/netdata/blob/master/collectors/statsd.plugin/README.md) server by default and we have included a default configuration file for k6 metrics. + +## Run the k6 test + +```bash +k6 run --out output-statsd script.js +``` + +Make sure you're using the k6 binary you built with the xk6-output-statsd extension. + +**Caveat**: By default, Netdata binds the StatsD server to `localhost`. That means that if Netdata and k6 are in different hosts, you will need to edit the configuration file of Netdata. + +1. Visit the [StatsD documentation](https://github.com/netdata/netdata/blob/master/collectors/statsd.plugin/README.md) for a reference on the configuration options. We are interested in the `#bind to` option. +2. Use `sudo ./edit-config netdata.conf` from inside the directory where Netdata stores its configuration files (e.g `/etc/netdata/`) and add `bind to=udp:0.0.0.0:8125`. + +## Visualize in Netdata + +Netdata will automatically create charts for your application, as illustrated in the [documentation](https://github.com/netdata/netdata/blob/master/collectors/statsd.plugin/k6.md). + +Simply head over to `localhost:19999` (assuming that you are running Netdata on the same machine) and find the k6 section. If you had opened Netdata before running the experiment, you will need to refresh the dashboard page. + +![image](https://user-images.githubusercontent.com/13405632/117691411-8a7baf00-b1c4-11eb-9d87-8e9e7214871f.png) + + + + diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 NewRelic.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 NewRelic.md new file mode 100644 index 0000000000..bed930850d --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 NewRelic.md @@ -0,0 +1,179 @@ +--- +title: 'New Relic' +excerpt: 'You can send k6 output to New Relic. With this integration visualize load test results and correlate them your New Relic telemetry data, create and share reports, and alert on k6 telemetry.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/new-relic/ +--- + +
+ +The built-in StatsD output has been deprecated on k6 v0.47.0. You can continue to use this feature by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd), and this guide has been updated to include instructions for how to use it. + +For more information on the reason behind this change, you can follow [this issue](https://github.com/grafana/k6/issues/2982) in the k6 repository. + +
+ +k6 can send telemetry data to [New Relic](https://newrelic.com/) through the New Relic [StatsD integration](https://docs.newrelic.com/docs/integrations/host-integrations/host-integrations-list/statsd-monitoring-integration-version-2). Within New Relic you can find your k6 performance data alongside your real users data and server side performance. This data can be visualized in dashboards and shared with others, used to compare load impact with system performance, and alert on metrics too. + +This guide covers running the New Relic integration: + +- Run the New Relic StatsD integration +- Run the k6 test +- Visualize k6 telemetry in New Relic + +## Before you begin + +To use the StatsD output option, you have to build a k6 binary using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd). For more details, refer to [StatsD](/results-output/real-time/statsd). + +## Run the New Relic StatsD integration + +To get k6 metrics into New Relic, k6 sends metrics to the New Relic StatsD integration which will take care of collecting, aggregate, format and send the telemetry to the New Relic Telemetry Data Platform. You can run this with or without a New Relic agent. + +Run the New Relic integration as a Docker container with this command: + + + +```bash +docker run --rm \ + -d --restart unless-stopped \ + --name newrelic-statsd \ + -h $(hostname) \ + -e NR_ACCOUNT_ID= \ + -e NR_API_KEY="" \ + -p 8125:8125/udp \ + newrelic/nri-statsd:latest +``` + + + +Replace `` with your [New Relic Account ID](https://docs.newrelic.com/docs/accounts/accounts-billing/account-setup/account-id#:~:text=If%20you%20have%20a%20single,account%20ID%20is%20displayed%20there.) and `` with your [New Relic Insert API Key](https://docs.newrelic.com/docs/insights/insights-data-sources/custom-data/introduction-event-api#register). + +If your account is hosted in the New Relic EU region, then also add this to the above command: `-e NR_EU_REGION=true \` + + +The _required_ environment variables used in the above command are: + +| Name | Value | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `NR_ACCOUNT_ID` | The Account ID used in New Relic You can find your account ID [here](https://docs.newrelic.com/docs/accounts/accounts-billing/account-setup/account-id#:~:text=If%20you%20have%20a%20single,account%20ID%20is%20displayed%20there.). | +| `NR_API_KEY` | The Insert API Key for your New Relic account to send k6 telemetry to the account ID specified above. You can generate an Insert API key [here](https://docs.newrelic.com/docs/insights/insights-data-sources/custom-data/introduction-event-api#register). | + +_Optional_ environment variables you can use: + +| Name | Value | +| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `NR_EU_REGION` | Setting this to `true` tells the integration your account is housed in the New Relic EU region. | +| `TAGS` | Setting tags in key:value format separated by a space lets you further understand your data in New Relic. For example identifying different test runs or machines running the tests. In the docker command add: `-e TAGS="k6Test:myExampleTest someKey:someValue" \`. | +| `NR_LOG_METRICS` | Setting this to `true` activates verbose logging for the integration. | +### About the New Relic integration + +The New Relic StatsD integration installed above can run standalone. Installing a New Relic agent is optional. + +Everything provided in the command above is enough to send k6 performance metrics to New Relic. You can optionally however [add further configuration](https://docs.newrelic.com/docs/integrations/host-integrations/host-integrations-list/statsd-monitoring-integration-version-2#configure), [further define metrics and their formats](https://docs.newrelic.com/docs/integrations/host-integrations/host-integrations-list/statsd-monitoring-integration-version-2#metric-format) (you can however do this on the New Relic side configuration), [add custom tags](https://docs.newrelic.com/docs/integrations/host-integrations/host-integrations-list/statsd-monitoring-integration-version-2#add-tags), and [create alerts](https://docs.newrelic.com/docs/integrations/host-integrations/host-integrations-list/statsd-monitoring-integration-version-2#alerts). This is covered in the optional table below. + +## Run the k6 test + +Once the integration is running, run the k6 test and send the metrics to the integration with: + + + +```bash +$ K6_STATSD_ENABLE_TAGS=true k6 run --out output-statsd script.js +``` + + + +Make sure you're using the k6 binary you built with the xk6-output-statsd extension. + +You can look at the [StatsD](/results-output/real-time/statsd) output page for configuration options. + +## Visualisation in New Relic + +As your k6 test is running, k6 is sending performance metrics to the New Relic StatsD integration which in turn is sending these metrics to the New Relic Telemetry Data Platform. These will be prefixed with `k6.` so you can identify them. + +![k6 metrics as seen in the New Relic data explorer](images/NewRelic/new-relic-data-explorer.png) + +You can visualize the metrics sent from this integration in the [data explorer](https://docs.newrelic.com/docs/insights/use-insights-ui/explore-data/metric-explorer-search-chart-metrics-sent-new-relic-agents) in the top right of New Relic (_query your data_). + +![Sample New Relic k6 dashboard](images/NewRelic/new-relic-dashboard.png) + +You can also add these metrics to [dashboards](https://docs.newrelic.com/docs/query-your-data/explore-query-data/dashboards/introduction-new-relic-one-dashboards) and [alert on k6 metrics](https://docs.newrelic.com/docs/alerts-applied-intelligence/new-relic-alerts/alert-conditions/create-nrql-alert-conditions). + +### Example NRQL Queries + +
+ +New Relic doesn't support calculating percentiles from metric data, which is the data format sent by this k6 output. See [this New Relic forum post](https://discuss.newrelic.com/t/percentiles-of-values-from-metrics-api-with-nrql-not-working/95832) and [the documentation about the metric data type](https://docs.newrelic.com/docs/data-apis/understand-data/metric-data/query-metric-data-type/) for details. + +
+ +Here are some example NRQL queries you can easily copy and paste into widgets in a New Relic dashboard, you can however stick with the [chart builder](https://docs.newrelic.com/docs/query-your-data/explore-query-data/query-builder/introduction-query-builder). Find all your k6 Metrics under the metrics tab, prefixed with `k6.` + +**Number of Virtual Users** + + + +```plain +SELECT latest(k6.vus) FROM Metric TIMESERIES +``` + + + +**Max, Median, and Average Request Duration** + + + +```plain +SELECT max(k6.http_req_duration.summary) AS 'Max Duration', average(k6.http_req_duration.median) AS 'Median', average(k6.http_req_duration.mean) AS 'Avg' FROM Metric TIMESERIES +``` + + + +**Rate of Requests** + + + +```plain +SELECT rate(max(k6.http_reqs), 1 seconds) FROM Metric TIMESERIES +``` + + + +**Data Sent and Data Received** + + + +```plain +SELECT sum(k6.data_received) as 'Data Received', max(k6.data_sent) AS 'Data Sent' FROM Metric TIMESERIES +``` + + + +**Histogram bucketing Requests** + + + +```plain +SELECT histogram(`k6.http_reqs`, 80, 20) FROM Metric +``` + + + +**Change in the number of Requests** + + + +```plain +SELECT derivative(k6.http_reqs, 30 seconds) AS 'Rate /reqs' FROM Metric TIMESERIES +``` + + + +**Scrolling List of all k6 Performance Metrics** + + + +```plain +SELECT uniques(metricName) FROM Metric WHERE metricName LIKE 'k6%' LIMIT MAX +``` + + diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Prometheus remote write.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Prometheus remote write.md new file mode 100644 index 0000000000..e56e55bea4 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 Prometheus remote write.md @@ -0,0 +1,257 @@ +--- +title: 'Prometheus remote write' +excerpt: 'Use the Prometheus remote write output to send test results to any Prometheus remote write endpoint.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/prometheus-remote-write/ +--- + + + +[Prometheus remote write](https://prometheus.io/docs/concepts/remote_write_spec/) is a protocol that makes it possible to reliably propagate data in real-time from a sender to a receiver. +It has multiple compatible [implementations](https://prometheus.io/docs/concepts/remote_write_spec/#compatible-senders-and-receivers) and [storage integrations](https://prometheus.io/docs/prometheus/latest/storage/#remote-storage-integrations). + +For instance, when using the `experimental-prometheus-rw` output, k6 can send test-result metrics to the remote-write endpoint and store them in Prometheus. + +The output, during the `k6 run` execution, gets all the generated time-series data points for the [k6 metrics](/using-k6/metrics/). +It then generates the equivalent Prometheus time series and sends them to the Prometheus remote write endpoint. + + +## Metrics mapping + +All [k6 metric types](/using-k6/metrics/) are converted into an equivalent [Prometheus metric type](https://prometheus.io/docs/concepts/metric_types/). +The output maps the metrics into time series with Name labels. +As much as possible, k6 respects the [naming best practices](https://prometheus.io/docs/practices/naming) that the Prometheus project defines: + +* All time series are prefixed with the `k6_` namespace. +* All time series are suffixed with the base unit of the sample value (if k6 knows what the base unit is). +* Trends and rates have the relative suffixes, to make them more discoverable. + +| k6 | Prometheus | Name label | +|---------|---------------------------|----------------------| +| Counter | Counter | `k6_*_total` | +| Gauge | Gauge | `k6_*_` | +| Rate | Gauge | `k6_*_rate` | +| Trend | [Counter and Gauges (default)](#counter-and-gauges) or [Native Histogram](#prometheus-native-histogram) | `k6_*_` | + +## Trend metric conversions + +This output provides two distinct mechanisms to send [k6 Trend metrics](/using-k6/metrics/) to Prometheus: + +1. [Counter and Gauge metrics](#counter-and-gauges) (default) +2. [Prometheus Native histogram](#prometheus-native-histogram) + +Both options provide efficient storage of test results while providing high-precision queries. + +Note that k6 aggregates trend metric data before sending it to Prometheus in both options. The reasons for aggregating data are: + +- Prometheus stores data in a millisecond precision (`ms`), but k6 metrics collect data points with higher accuracy, nanosecond (`ns`). +- A load test could generate vast amounts of data points. High-precision raw data could quickly become expensive and complex to scale and is unnecessary when analyzing performance trends. + +### 1. Counter and gauges + +By default, Prometheus supports [Counter and Gauge Metric types](https://prometheus.io/docs/concepts/metric_types/). Therefore, this option is the default of this output and converts all the k6 `Trend` metrics to Counter and Gauges Prometheus metrics. + +You can configure how to convert all the k6 trend metrics with the [`K6_PROMETHEUS_RW_TREND_STATS` option](#options) that accepts a comma-separated list of stats functions: `count`, `sum`, `min`, `max`, `avg`, `med`, `p(x)`. The default is `p(99)`. + + +Given the list of stats functions, k6 converts all trend metrics to the respective math functions as Prometheus metrics. + + +For example, `K6_PROMETHEUS_RW_TREND_STATS=p(90),p(95),max` transforms each trend metric into three Prometheus metrics as follows: + +- `k6_*_p90` +- `k6_*_p95` +- `k6_*_max` + +This option provides a configurable solution to represent `Trend` metrics in Prometheus but has the following drawbacks: +- Convert a k6 `Trend` metric to several Prometheus metrics. +- It is impossible to aggregate some gauge values (especially percentiles). +- It uses a memory-expensive k6 data structure. + +### 2. Prometheus native histogram + + +To address the limitations of the previous option, you can convert k6 trend metrics to high-fidelity histograms enabling [Prometheus native histograms](https://prometheus.io/docs/concepts/metric_types/#histogram). + +With this option, each k6 trend metric maps to its corresponding Prometheus histogram metric: `k6_*`. You can then query them using Prometheus histogram functions, such as [histogram_quantile()](https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile). + + +
+ +🌟 To learn the benefits and outcomes of using Histograms, watch [High-resolution Histograms in Prometheus](https://www.youtube.com/watch?v=F72Tk8iaWeA). + +⚠️ Note that Native Histogram is an experimental feature released in Prometheus v2.40.0, and other remote write implementations might not support it yet. In the future, when Prometheus makes this feature stable, k6 will consider using it as the default conversion method for Trend metrics. + +
+ + +## Send test metrics to a remote write endpoint + +To use remote write in Prometheus 2.x, enable the feature flag [--web.enable-remote-write-receiver](https://prometheus.io/docs/prometheus/latest/feature_flags/#remote-write-receiver). For remote write storage options, refer to the [Prometheus docs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). + +1. To send k6 metrics to a **remote write endpoint without native histograms**: + - Set up a running remote write endpoint and ensure k6 can reach it. + + - Run your k6 script with the `--out` flag and the URL of the RW endpoint as follows: + + + + ```bash + K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \ + k6 run -o experimental-prometheus-rw script.js + ``` + + ```bash + K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \ + K6_PROMETHEUS_RW_USERNAME=USERNAME \ + K6_PROMETHEUS_RW_PASSWORD=PASSWORD \ + k6 run -o experimental-prometheus-rw script.js + ``` + + + + - Optionally, pass the `K6_PROMETHEUS_RW_TREND_STATS` to gain the ability to query additional stats for trend metrics. The default is `p(99)`. + + + + ```bash + K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \ + K6_PROMETHEUS_RW_TREND_STATS=p(95),p(99),min,max \ + k6 run -o experimental-prometheus-rw script.js + ``` + + + +2. To send k6 metrics to a **remote write endpoint with native histograms**: + - Enable the feature flag [--enable-feature=native-histograms](https://prometheus.io/docs/prometheus/latest/feature_flags/#native-histograms) in Prometheus 2.40.0 or higher. Set up a running remote write endpoint and ensure k6 can reach it. + + - Run your k6 script with the `--out` flag, enabling the `K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM` option, and the URL of the RW endpoint as follows: + + + + ```bash + K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \ + K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true \ + k6 run -o experimental-prometheus-rw script.js + ``` + + ```bash + K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \ + K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true \ + K6_PROMETHEUS_RW_USERNAME=USERNAME \ + K6_PROMETHEUS_RW_PASSWORD=PASSWORD \ + k6 run -o experimental-prometheus-rw script.js + ``` + + + + +When running the previous `k6 run` commands, k6 starts sending time-series metrics to Prometheus. +All the time series have a [`k6_` prefix](#metrics-mapping). +In the Prometheus Web UI, they appear like this: + +![k6 metrics as seen in the Prometheus UI](images/Prometheus/query-k6-metrics-in-the-prometheus-web-ui.png) + + +## Options + +k6 has special options for remote write output. + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `K6_PROMETHEUS_RW_SERVER_URL` | `string` | URL of the Prometheus remote write implementation's endpoint. Default is ``http://localhost:9090/api/v1/write`` | +| `K6_PROMETHEUS_RW_HEADERS_` | `string` | Additional header to include in the HTTP requests. It can be set using the described format, for example `K6_PROMETHEUS_RW_HEADERS_CUSTOM-HEADER-KEY=custom-header-value`. | +| `K6_PROMETHEUS_RW_HTTP_HEADERS` | A comma-separated list of key-values | Additional headers to include in the HTTP requests. `K6_PROMETHEUS_RW_HTTP_HEADERS=key1:value1,key2:value2`. | +| `K6_PROMETHEUS_RW_PUSH_INTERVAL` | `string` | Interval between the metrics' aggregation and upload to the endpoint. Default is `5s`. | +| `K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM` | `boolean` | If true, maps all the defined trend metrics as [Native Histograms](#prometheus-native-histogram). Default is `false`. | +| `K6_PROMETHEUS_RW_TREND_STATS` | list of `string` | If Native Histogram is not enabled, then it defines the stats functions to map for all of the defined trend metrics. It's a comma-separated list of stats functions to include (e.g. `p(90),avg,sum`). Check the trend section to see the list of supported stats. Default is `p(99)`. | +| `K6_PROMETHEUS_RW_INSECURE_SKIP_TLS_VERIFY` | `boolean` | If true, the HTTP client skips TLS verification on the endpoint. Default is `false`. | +| `K6_PROMETHEUS_RW_STALE_MARKERS` | `boolean` | If true, the output at the end of the test marks all the seen time series as stale. Default is `false`. | +| `K6_PROMETHEUS_RW_USERNAME` | `string` | Username for the HTTP Basic authentication at the Prometheus remote write endpoint. | +| `K6_PROMETHEUS_RW_PASSWORD` | `string` | Password for the HTTP Basic authentication at the Prometheus remote write endpoint. | +| `K6_PROMETHEUS_RW_CLIENT_CERTIFICATE` | `string` | A path to the PEM (Privacy-Enhanced Mail) formatted client certificate. | +| `K6_PROMETHEUS_RW_CLIENT_CERTIFICATE_KEY` | `string` | A path to the PEM formatted client private key. | +| `K6_PROMETHEUS_RW_BEARER_TOKEN` | `string` | Sets the Authorization Bearer Token Header. | + +### Stale trend metrics + +This k6 output can mark the time series at the end of the test as stale. +To enable the stale marker option, set the `K6_PROMETHEUS_RW_STALE_MARKERS` environment variable to `true`. + +By default, the metrics are active for 5 minutes after the last flushed sample. +They are automatically marked as stale after. +For details about staleness, refer to the [Prometheus docs](https://prometheus.io/docs/prometheus/latest/querying/basics/#staleness). + +## Time series visualization + +To visualize time series with Grafana, you can use the [Explore UI](https://grafana.com/docs/grafana/latest/explore/) or import any of the existing pre-built dashboards: +- [k6 Prometheus dashboard by Grafana k6](https://grafana.com/grafana/dashboards/19665-k6-prometheus/) +- [k6 Prometheus (Native Histograms) dashboard by Grafana k6](https://grafana.com/grafana/dashboards/18030-k6-prometheus-native-histograms/) +- [Other public dashboards available from the community](https://grafana.com/grafana/dashboards/?search=k6&dataSource=prometheus) + +If you are a Grafana Cloud user, please refer to the [Grafana Cloud Prometheus docs](/results-output/real-time/grafana-cloud-prometheus). + +For a local environment, the [`xk6-output-prometheus-remote` repository](https://github.com/grafana/xk6-output-prometheus-remote) includes a docker-compose setup that provisions the `k6 Prometheus` and `k6 Prometheus (Native Histograms)` dashboards: + +![Provisioned k6 Prometheus Dashboards](./images/Prometheus/list-provisioned-prometheus-dashboards.png) + +### Docker compose example + +Clone the repository to get started and follow these steps for using the [docker-compose.yml](https://github.com/grafana/xk6-output-prometheus-remote/blob/main/docker-compose.yml) file that starts _Prometheus_ and _Grafana_: + +1. Start the docker compose environment. + + + + ```shell + docker compose up -d prometheus grafana + ``` + + + + + + ```shell + # Output + Creating xk6-output-prometheus-remote_grafana_1 ... done + Creating xk6-output-prometheus-remote_prometheus_1 ... done + ``` + + + + Prometheus is started with Native Histogram enabled. You can use the same Prometheus instance to receive k6 trend metrics as native histograms or multiple metric stats. + +2. Run the k6 test with one of the options detailed on [Send test metrics to a remote write endpoint](#send-test-metrics-to-a-remote-write-endpoint). + + + + ```bash + K6_PROMETHEUS_RW_TREND_STATS=p(95),p(99),min,max \ + k6 run -o experimental-prometheus-rw script.js + ``` + + ```bash + K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true \ + k6 run -o experimental-prometheus-rw script.js + ``` + + + + Optionally, you can set the `testid` tag as a [wide test tag](https://k6.io/docs/using-k6/tags-and-groups/#test-wide-tags) to segment metrics into discrete test runs and filter specific test results on the pre-built Grafana dashboards or in PromQL queries. `testid` can be any unique string that let you clearly identify the test run. + + + + ```bash + K6_PROMETHEUS_RW_TREND_STATS=p(95),p(99),min,max \ + k6 run -o experimental-prometheus-rw --tag testid= script.js + ``` + + ```bash + K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM=true \ + k6 run -o experimental-prometheus-rw --tag testid= script.js + ``` + + + +3. After running the test, visit [http://localhost:3000](http://localhost:3000). If you enabled native histograms, select the **k6 Prometheus (Native Histograms)** dashboard; otherwise, select the **k6 Prometheus** Dashboard. + +![k6 Prometheus Dashboard](./images/Prometheus/k6-prometheus-dashboard.png) diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 StatsD.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 StatsD.md new file mode 100755 index 0000000000..3d258f03ac --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 StatsD.md @@ -0,0 +1,42 @@ +--- +title: 'StatsD' +excerpt: 'k6 has a built-in output to a StatsD service.' +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/statsd/ +--- + +
+ +The built-in StatsD output has been deprecated on k6 v0.47.0. You can continue to use this feature by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd), and this guide has been updated to include instructions for how to use it. + +For more information on the reason behind this change, you can follow [this issue](https://github.com/grafana/k6/issues/2982) in the k6 repository. + +
+ +k6 can push test metrics to a [StatsD](https://github.com/statsd/statsd) service by using the [xk6-output-statsd extension](https://github.com/LeonAdato/xk6-output-statsd). + +## Build the k6 version + + + +## Run the k6 test + +Using the k6 binary you built in the previous step, you can use the `--out output-statsd` option when running your tests to use this extension: + + + +```bash +$ ./k6 run --out output-statsd script.js +``` + + + +The following options can be configured: + +| Name | Value | +| ------------------------- | ------------------------------------------------------------------------------------------------------ | +| `K6_STATSD_ADDR` | Address of the statsd service, currently only UDP is supported. The default value is `localhost:8125`. | +| `K6_STATSD_NAMESPACE` | The namespace used as a prefix for all the metric names. The default value is `k6`. | +| `K6_STATSD_PUSH_INTERVAL` | Configure how often data batches are sent. The default value is `1s`. | +| `K6_STATSD_BUFFER_SIZE` | The buffer size. The default value is `20`. | +| `K6_STATSD_ENABLE_TAGS` | If `true` enables sending tags. `false` by default as old versions of statsd, prior to v0.9.0 did not support tags. | +| `K6_STATSD_TAG_BLOCKLIST` | This is a comma-separated list of tags that should NOT be sent to statsd. For example, "tag1,tag2". The default value is `vu,iter,url`. | diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 TimescaleDB.md b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 TimescaleDB.md new file mode 100755 index 0000000000..c3ce3247f9 --- /dev/null +++ b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/00 TimescaleDB.md @@ -0,0 +1,52 @@ +--- +title: 'TimescaleDB' +excerpt: k6 has an output extension to store k6 metrics in TimescaleDB. This document shows you how to configure the k6 TimescaleDB integration. +canonicalUrl: https://grafana.com/docs/k6/latest/results-output/real-time/timescaledb/ +--- + +Using the [TimescaleDB k6 extension](https://github.com/grafana/xk6-output-timescaledb), you can store k6 metrics in [TimescaleDB](https://www.timescale.com/) and analyze your performance results with SQL and dashboards. The extension repository includes two Grafana dashboards. + + +## Build the k6 version + + + +## Run the test + +Check that the TimescaleDB instance is running. Copy the Postgres connection string of the database, which will store the k6 metrics. + +Use the previous k6 binary and run the test passing the Postgres connection string to the [output option](/using-k6/k6-options/reference#results-output) as follows: + + +```bash +k6 run script.js -o timescaledb=postgresql://:@:/ +``` + +k6 runs the test script and sends the metrics in real-time to the TimescaleDB instance. You can now connect to TimescaleDB and query the [k6 metrics](/using-k6/metrics/). + +```bash +k6=# SELECT metric,AVG (value) FROM samples GROUP BY metric; +``` + +### Options + +Here is the full list of options that can be configured and passed to the extension: + +| Name | Value | +| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `K6_TIMESCALEDB_PUSH_INTERVAL` | Define how often metrics are sent to TimescaleDB. The default value is 1s (1 second). | + +## Grafana Dashboards + +The extension repository includes a [docker-compose setup](https://github.com/grafana/xk6-output-timescaledb/#docker-compose) with two pre-built dashboards to: +- list test runs +- visualize the results of a test run + + +![TimescaleDB list test runs](./images/TimescaleDB/dashboard-test-runs.png) + +![TimescaleDB k6 results](./images/TimescaleDB/dashboard-test-result.png) + +## Read more + +- [Store k6 metrics in TimescaleDB and visualize with Grafana](https://k6.io/blog/store-k6-metrics-in-timescaledb-and-visualize-with-grafana/) diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Cloud/screenshot-stream-k6-results-to-grafana-cloud-k6.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Cloud/screenshot-stream-k6-results-to-grafana-cloud-k6.png new file mode 100644 index 0000000000..275890299c Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Cloud/screenshot-stream-k6-results-to-grafana-cloud-k6.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/CloudWatch/cloudwatch-k6-dashboard.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/CloudWatch/cloudwatch-k6-dashboard.png new file mode 100644 index 0000000000..ce1ee7e6fd Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/CloudWatch/cloudwatch-k6-dashboard.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/CloudWatch/cloudwatch-k6-metrics.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/CloudWatch/cloudwatch-k6-metrics.png new file mode 100644 index 0000000000..80629bdde2 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/CloudWatch/cloudwatch-k6-metrics.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/DataDog/datadog-performance-testing-metrics.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/DataDog/datadog-performance-testing-metrics.png new file mode 100644 index 0000000000..be1a6226a2 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/DataDog/datadog-performance-testing-metrics.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/DataDog/k6-datadog-dashboard.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/DataDog/k6-datadog-dashboard.png new file mode 100644 index 0000000000..eae403e37b Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/DataDog/k6-datadog-dashboard.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-api-token.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-api-token.png new file mode 100644 index 0000000000..0bbe457450 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-api-token.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-k6-metrics.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-k6-metrics.png new file mode 100644 index 0000000000..f86535d7b7 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-k6-metrics.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-k6-test-result.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-k6-test-result.png new file mode 100644 index 0000000000..c5bbe92cce Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Dynatrace/dynatrace-k6-test-result.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Elasticsearch/kibana-discover-test-result.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Elasticsearch/kibana-discover-test-result.png new file mode 100644 index 0000000000..a79f97825d Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Elasticsearch/kibana-discover-test-result.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_create_api_key_metrics_publisher.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_create_api_key_metrics_publisher.png new file mode 100644 index 0000000000..2700fc7d34 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_create_api_key_metrics_publisher.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6.png new file mode 100644 index 0000000000..5cc38196f1 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6_metrics.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6_metrics.png new file mode 100644 index 0000000000..ece01d3e32 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6_metrics.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6_metrics_from_extension.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6_metrics_from_extension.png new file mode 100644 index 0000000000..b94d8565e1 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_explore_k6_metrics_from_extension.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_portal.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_portal.png new file mode 100644 index 0000000000..05d8b32f5a Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_portal.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_prometheus_configuration.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_prometheus_configuration.png new file mode 100644 index 0000000000..f9dcbed57e Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/GrafanaCloud/grafana_cloud_prometheus_configuration.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-configure-graph-panel.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-configure-graph-panel.png new file mode 100644 index 0000000000..47345faefd Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-configure-graph-panel.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-create-data-source.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-create-data-source.png new file mode 100644 index 0000000000..7e4c784994 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-create-data-source.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-dave.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-dave.png new file mode 100644 index 0000000000..22f61b79e4 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-dave.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-edit-metric.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-edit-metric.png new file mode 100644 index 0000000000..c09e0ca532 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-edit-metric.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-new-dashboard.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-new-dashboard.png new file mode 100644 index 0000000000..f94c32b4ae Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-new-dashboard.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-new-graph-panel.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-new-graph-panel.png new file mode 100644 index 0000000000..61d3b3d047 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-new-graph-panel.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-visualization.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-visualization.png new file mode 100644 index 0000000000..f0d1492687 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB-Grafana/grafana-visualization.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB/influxdb-data-explorer-k6-bucket.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB/influxdb-data-explorer-k6-bucket.png new file mode 100644 index 0000000000..7f53bce1ac Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/InfluxDB/influxdb-data-explorer-k6-bucket.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/NewRelic/new-relic-dashboard.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/NewRelic/new-relic-dashboard.png new file mode 100644 index 0000000000..41cce0502c Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/NewRelic/new-relic-dashboard.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/NewRelic/new-relic-data-explorer.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/NewRelic/new-relic-data-explorer.png new file mode 100644 index 0000000000..2f18c458a3 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/NewRelic/new-relic-data-explorer.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard-part1.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard-part1.png new file mode 100644 index 0000000000..167ab588a3 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard-part1.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard-part2.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard-part2.png new file mode 100644 index 0000000000..83c419efbb Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard-part2.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard.png new file mode 100644 index 0000000000..89970e7aa8 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/k6-prometheus-dashboard.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/list-provisioned-prometheus-dashboards.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/list-provisioned-prometheus-dashboards.png new file mode 100644 index 0000000000..f7dab8335c Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/list-provisioned-prometheus-dashboards.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/prom-dashboard-test-result.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/prom-dashboard-test-result.png new file mode 100644 index 0000000000..5103765423 Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/prom-dashboard-test-result.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/prom-metric-explorer.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/prom-metric-explorer.png new file mode 100644 index 0000000000..0aa86f197a Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/prom-metric-explorer.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/query-k6-metrics-in-the-prometheus-web-ui.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/query-k6-metrics-in-the-prometheus-web-ui.png new file mode 100644 index 0000000000..e373f629eb Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/Prometheus/query-k6-metrics-in-the-prometheus-web-ui.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/TimescaleDB/dashboard-test-result.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/TimescaleDB/dashboard-test-result.png new file mode 100644 index 0000000000..f55e25039d Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/TimescaleDB/dashboard-test-result.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/TimescaleDB/dashboard-test-runs.png b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/TimescaleDB/dashboard-test-runs.png new file mode 100644 index 0000000000..5e350b1a5f Binary files /dev/null and b/src/data/markdown/translated-guides/en/04 Results output/200 Real-time/images/TimescaleDB/dashboard-test-runs.png differ diff --git a/src/data/markdown/translated-guides/en/04 Results output/300 Grafana dashboards.md b/src/data/markdown/translated-guides/en/04 Results output/300 Grafana dashboards.md index 060723bbdc..86834818c1 100644 --- a/src/data/markdown/translated-guides/en/04 Results output/300 Grafana dashboards.md +++ b/src/data/markdown/translated-guides/en/04 Results output/300 Grafana dashboards.md @@ -2,7 +2,6 @@ title: Grafana dashboards excerpt: With multiple k6 output formats, you also have multiple ways to visualize test results in a Grafana dashboard. canonicalUrl: https://grafana.com/docs/k6/latest/results-output/grafana-dashboards/ -redirect: https://grafana.com/docs/k6/latest/results-output/grafana-dashboards/ --- You have multiple ways to query k6 results in Grafana. diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/01 test builder.md b/src/data/markdown/translated-guides/en/05 Test authoring/01 test builder.md index 72244d0559..61edada43d 100644 --- a/src/data/markdown/translated-guides/en/05 Test authoring/01 test builder.md +++ b/src/data/markdown/translated-guides/en/05 Test authoring/01 test builder.md @@ -2,7 +2,6 @@ title: 'Test builder' excerpt: 'Use a graphical interface to create a k6 test.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/test-authoring/test-builder/ -redirect: https://grafana.com/docs/k6/latest/using-k6/test-authoring/test-builder/ --- The k6 Test Builder provides a graphical interface to generate a k6 test script based on your input. Then, you can copy the test script and [run the test from the CLI](/get-started/running-k6). diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings.md b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings.md index 0d94df3359..d182583f16 100644 --- a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings.md +++ b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings.md @@ -2,7 +2,6 @@ title: 'Create tests from recordings' excerpt: 'In load testing, recording usually refers to the process of creating a load test from the recording of a user session.' canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/test-authoring/create-tests-from-recordings/ -redirect: https://grafana.com/docs/k6/latest/using-k6/test-authoring/create-tests-from-recordings/ --- A recording stores the sequence of requests and parameters of a user session or API interaction. diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/01 Using the browser recorder.md b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/01 Using the browser recorder.md new file mode 100644 index 0000000000..0627fc1723 --- /dev/null +++ b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/01 Using the browser recorder.md @@ -0,0 +1,45 @@ +--- +title: 'Using the browser recorder' +excerpt: 'The browser recorder allows generating a k6 script based on a web session. It is available as extensions for Chrome and Firefox.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/test-authoring/create-tests-from-recordings/using-the-browser-recorder/ +--- + +The browser recorder lets you generate a k6 script based on a browser session. +It's available as an extension for [Chrome](https://chrome.google.com/webstore/detail/grafana-k6-browser-record/fbanjfonbcedhifbgikmjelkkckhhidl) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/grafana-k6-browser-recorder/). + + +## Before you start + + +Before you start, consider the following: + +- [Be sure to record realistically](/test-authoring/create-tests-from-recordings/#be-sure-to-record-realistically) +- [A hybrid approach for load testing websites](/test-authoring/create-tests-from-recordings/#consider-hybrid-approach-for-load-testing-websites) + +> Note that the browser recorders **do not require a cloud account**. For cloud users, check out the [Grafana Cloud](https://grafana.com/docs/grafana-cloud/k6/author-run/browser-recorder/) and [k6 Cloud](/cloud/creating-and-running-a-test/browser-recorder/) instructions. + +## How to record + +1. Install the [Chrome](https://chrome.google.com/webstore/detail/grafana-k6-browser-record/fbanjfonbcedhifbgikmjelkkckhhidl) or [Firefox](https://addons.mozilla.org/en-US/firefox/addon/grafana-k6-browser-recorder/) extension. +1. Open the extension by clicking the k6 logo. +2. Choose where to save the auto-generated script. + - To save it on your local machine, select **I don't want to save tests in the cloud**. + - To save it on any of your Grafana Cloud k6 projects, select **Sign In**. +3. Select **Start recording** to begin recording the current browser tab. +4. When done, select **Stop recording**. +5. Save the recorded script locally or in any of your cloud projects. +6. Edit your script as necessary. Depending on the [type of load test](/test-types/load-test-types/), you might need to change different aspects of the script. + Typical changes are for [load options](/using-k6/options) and to handle [correlation and dynamic data](/examples/correlation-and-dynamic-data). +7. Run the test from the CLI or Grafana Cloud k6. For more about running k6, refer to the [Running k6 guide](/get-started/running-k6). + +## Troubleshooting. Try the HAR converter + + +If you experience problems recording a request, try the [HAR converter](/test-authoring/create-tests-from-recordings/using-the-har-converter/). + +The Browser recorder uses the HAR converter under the hood. +Like the Browser Recorder, the HAR converter creates a k6 script from the HTTP requests included in a HAR file. + +The HAR converter can also record other tabs or pop-up windows, which the Browser Recorder cannot. + +If the error persists with the HAR converter, please provide detailed information about the problem [in a new issue](https://github.com/k6io/har-to-k6/issues). diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/02 Using the HAR converter.md b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/02 Using the HAR converter.md new file mode 100644 index 0000000000..2d7de6c39b --- /dev/null +++ b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/02 Using the HAR converter.md @@ -0,0 +1,159 @@ +--- +title: 'Using the HAR converter' +excerpt: 'The HAR converter is an alternative to the Browser recorder. It generates a k6 script based on the HTTP requests included on a HAR file.' +canonicalUrl: https://grafana.com/docs/k6/latest/using-k6/test-authoring/create-tests-from-recordings/using-the-har-converter/ +--- + +The [har-to-k6 converter](https://github.com/k6io/har-to-k6) is a NodeJS tool that generates a k6 script based on the HTTP requests included in a [HAR file](). +It is an alternative to the [Browser recorder](/test-authoring/create-tests-from-recordings/using-the-browser-recorder/). + +> HAR is a file format used by all major browsers and various other tools to export recorded HTTP requests. + +## Before you start + +Before you start, consider the following: + +- [Be sure to record realistically](/test-authoring/create-tests-from-recordings/#be-sure-to-record-realistically) +- [A hybrid approach for load testing websites](/test-authoring/create-tests-from-recordings/#consider-hybrid-approach-for-load-testing-websites) + +You'll need to choose a tool to record your HAR file. +Multiple browsers and tools can export HTTP traffic in a HAR format. +A few popular ones are: + +- [Chrome](https://www.google.com/chrome/) +- [Firefox](https://www.mozilla.org/en-US/firefox/) +- [Microsoft Edge](https://www.microsoft.com/en-us/edge) +- [Charles recording proxy](http://www.charlesproxy.com/)(HTTP proxy/recorder) +- [Fiddler](http://www.telerik.com/fiddler) (HTTP proxy/recorder) + + + +## 1. Record a HAR file + +Here are the basic steps you need to record in Chrome: + +1. Open a new incognito window in Chrome. (This is optional, but it means you won't send things like cookies, which your browser might have saved). +1. Open up Chrome developer tools (press F12). +1. Select the **Network** tab. +1. Check that the recording button (round button) is activated (red color). +1. If you want to make a recording of several successive page loads, select the **Preserve log** checkbox. +1. Enter the URL of your site and start doing whatever you want your simulated load-test users to do. +1. When done, in Chrome developer tools, right-click the URLs and choose **Save as HAR with content**. + +![Save HAR for load testing](./images/session_recorder_save_as_har.png) + + +## 2. Convert with `har-to-k6` + +The [har-to-k6 converter](https://github.com/k6io/har-to-k6) is a NodeJS tool that can convert a HAR file (browser session) into a k6 script. + +1. Make sure that you have installed NodeJS (version >=11.0.0). +1. Install the converter. You can use `npm`: + + ```bash + $ npm install -g har-to-k6 + ``` + + For other installation options, check out the [har-to-k6 installation instructions](https://github.com/k6io/har-to-k6#installation). +1. Generate a k6 script from a HAR file with the convert command: + + ```bash + $ har-to-k6 myfile.har -o loadtest.js + ``` + +This command auto-generates a k6 script for you. +It reads the HAR file (_myfile.har_) and converts it into a k6 test (_loadtest.js_). + +## 3. Modify the auto-generated k6 script + +In the previous step, the converter created a k6 script for testing. +Now, you should evaluate whether you have to change any part of the k6 script. + +Depending on your use case, you might need to: + +- Configure the load options +- Remove third-party content +- Correlate dynamic data + +### Configure the load options + +Now, k6 has auto-generated a "functional" test. +By default, this test runs with one virtual user and for one iteration. + +It's time for you to configure the load options of your performance tests. +k6 lets you configure this in several ways: + +* As CLI arguments while running the test: + + ```bash + k6 run --vus 10 --duration 30s loadtest.js + ``` + +* As options in the script file. + + ```javascript + export const options = { + vus: 10, + duration: '30s', + }; + ``` + +To learn more about how to configure the load options, read the [Adding more VUs guide](/get-started/running-k6#adding-more-vus) and the [Options guide](/using-k6/options). + +### Remove third-party content + +If you are recording a user session of a website, by default, you'll record all the HTTP requests that your website uses. +This includes requests from the third-party tools that your site uses, +e.g. analytics tools, Facebook, Twitter, Support Widgets, CDNs, etc. + +You should remove these third party requests: + +- They will skew the percentiles of your performance results. +- You may be unable to affect the performance of the third-party service. +- The load test may violate the terms-of-service contract that you have with the provider. + +Your k6 script can skip third-party requests in a few ways: + +* Edit the auto-generated k6 script, removing the requests one-by-one +* Download a HAR file with only requests to the selected domains. + +In Chrome, you can use the DevTools Network Filter to select only particular domains. +The Filter input accepts a Regex to match multiple domains. + +```bash +/loadimpact.com|cloudfront.net/ +``` + +![Save HAR filter domain using regex](./images/session_recorder_filter_domain.png) + +After filtering your selected domains, you can download the HAR file as described in the first step of this tutorial. +The HAR file will include only the requests to the selected domains. + +If you don't know all the domains to filter, it helps to use the query language of the Network Filter. +Just input `domain:` in the filter to see all the different domains recorded by the Network Panel. + +![Save HAR filter domain list](./images/session_recorder_filter_domain_list.png) + +### Correlate dynamic data + +In load testing, _correlation_ is when you extract the value from the response of one request and reuse it in a subsequent request. +Often, the correlation would be for a token or ID that is needed to run a sequence of steps in a user journey. + +The recorded HAR file may include dynamic data used on your site - `IDs`, `CSRF tokens`, `VIEWSTATE`, `wpnonce`, and other `dynamic values` - that will be converted into the k6 script. + +To run your load test correctly, you may need to replace some recorded data with dynamic data that k6 gets from previous requests. +For example, tokens expire quickly, and they are one of the most common things that users will correlate from a recorded session. + +[Here](/examples/correlation-and-dynamic-data) are a few examples using the k6 API to correlate dynamic data. + +## 4. Run the test + +Now, you can run your load test with k6. If you have not installed k6 yet, please, follow the [k6 installation instructions](/get-started/installation). + +Execute the `k6 run` command to run your k6 script: + +```bash +$ k6 run loadtest.js +``` + +To learn about running k6, check out the [Running k6 tutorial](/get-started/running-k6). diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-2.png b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-2.png new file mode 100644 index 0000000000..ba280d0eb9 Binary files /dev/null and b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-2.png differ diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-3.png b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-3.png new file mode 100644 index 0000000000..270bd41c59 Binary files /dev/null and b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-3.png differ diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-4.png b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-4.png new file mode 100644 index 0000000000..dec2dd5f95 Binary files /dev/null and b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/Recording-a-test-script/step-4.png differ diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_filter_domain.png b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_filter_domain.png new file mode 100644 index 0000000000..403b2cef3a Binary files /dev/null and b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_filter_domain.png differ diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_filter_domain_list.png b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_filter_domain_list.png new file mode 100644 index 0000000000..6ce3fcde4a Binary files /dev/null and b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_filter_domain_list.png differ diff --git a/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_save_as_har.png b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_save_as_har.png new file mode 100644 index 0000000000..9f42d55a07 Binary files /dev/null and b/src/data/markdown/translated-guides/en/05 Test authoring/02 Create tests from recordings/images/session_recorder_save_as_har.png differ diff --git a/src/data/markdown/translated-guides/en/07 Testing Guides/01 API load testing.md b/src/data/markdown/translated-guides/en/07 Testing Guides/01 API load testing.md index 67defc34de..91a2ad99a7 100644 --- a/src/data/markdown/translated-guides/en/07 Testing Guides/01 API load testing.md +++ b/src/data/markdown/translated-guides/en/07 Testing Guides/01 API load testing.md @@ -3,7 +3,6 @@ title: 'API load testing' head_title: 'Intro to API Load Testing: The k6 Guide' excerpt: 'Load testing APIs has many facets. This guide introduces you to performance testing and provides best practices to load test your APIs with k6.' canonicalUrl: https://grafana.com/blog/2024/01/30/api-load-testing/ -redirect: https://grafana.com/blog/2024/01/30/api-load-testing/ --- An API load test generally starts with small loads on isolated components. diff --git a/src/data/markdown/translated-guides/en/07 Testing Guides/02 Automated performance testing.md b/src/data/markdown/translated-guides/en/07 Testing Guides/02 Automated performance testing.md index a6b437563b..f0e4fb4e62 100644 --- a/src/data/markdown/translated-guides/en/07 Testing Guides/02 Automated performance testing.md +++ b/src/data/markdown/translated-guides/en/07 Testing Guides/02 Automated performance testing.md @@ -3,7 +3,6 @@ title: 'Automated performance testing' head_title: 'How to Automate Performance Testing: The k6 Guide' excerpt: 'Performance testing automation is about establishing a repeatable and consistent process that checks reliability issues at different stages of the development and release cycle.' canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/automated-performance-testing/ -redirect: https://grafana.com/docs/k6/latest/testing-guides/automated-performance-testing/ --- diff --git a/src/data/markdown/translated-guides/en/07 Testing Guides/03 Load testing websites.md b/src/data/markdown/translated-guides/en/07 Testing Guides/03 Load testing websites.md index 00a63f9c0f..5517c82523 100644 --- a/src/data/markdown/translated-guides/en/07 Testing Guides/03 Load testing websites.md +++ b/src/data/markdown/translated-guides/en/07 Testing Guides/03 Load testing websites.md @@ -3,7 +3,6 @@ title: 'Load testing websites' head_title: 'How to Load Test a Website: The k6 Guide' excerpt: 'Do you know how many users your site can handle? This guide answers the WHY and WHEN you should load test your website and gives you the best practices for load testing websites or web apps with k6. Let’s get started.' canonicalUrl: https://grafana.com/blog/2024/01/30/load-testing-websites/ -redirect: https://grafana.com/blog/2024/01/30/load-testing-websites/ --- This doc explains some key concepts about load testing websites, including: diff --git a/src/data/markdown/translated-guides/en/07 Testing Guides/04 Running large tests.md b/src/data/markdown/translated-guides/en/07 Testing Guides/04 Running large tests.md index cb54049009..e3c8479a27 100644 --- a/src/data/markdown/translated-guides/en/07 Testing Guides/04 Running large tests.md +++ b/src/data/markdown/translated-guides/en/07 Testing Guides/04 Running large tests.md @@ -2,7 +2,6 @@ title: 'Running large tests' excerpt: 'How to run large-scale k6 tests without distributed-execution' canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/running-large-tests/ -redirect: https://grafana.com/docs/k6/latest/testing-guides/running-large-tests/ --- k6 can generate a lot of load from a single machine. With proper monitoring and script optimization, you might be able to run a rather large load test without needing [distributed execution](#distributed-execution). This document explains how to launch such a test, and some of the aspects you should be aware of. diff --git a/src/data/markdown/translated-guides/en/07 Testing Guides/05 Running distributed tests.md b/src/data/markdown/translated-guides/en/07 Testing Guides/05 Running distributed tests.md index 6748da9f11..2986b16f93 100644 --- a/src/data/markdown/translated-guides/en/07 Testing Guides/05 Running distributed tests.md +++ b/src/data/markdown/translated-guides/en/07 Testing Guides/05 Running distributed tests.md @@ -2,7 +2,6 @@ title: 'Running distributed tests' excerpt: 'How to run distributed tests in Kubernetes' canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/running-distributed-tests/ -redirect: https://grafana.com/docs/k6/latest/testing-guides/running-distributed-tests/ --- It has already been established that k6 can [run large load tests](/testing-guides/running-large-tests/) from a single instance, but what about _multiple instances running a single test_? diff --git a/src/data/markdown/translated-guides/en/08 Misc/01 Usage collection.md b/src/data/markdown/translated-guides/en/08 Misc/01 Usage collection.md index 6af6a2f924..0d367e25ed 100644 --- a/src/data/markdown/translated-guides/en/08 Misc/01 Usage collection.md +++ b/src/data/markdown/translated-guides/en/08 Misc/01 Usage collection.md @@ -2,7 +2,6 @@ title: 'Usage collection' excerpt: 'By default, k6 sends a usage report each time it is run, so that we can track how often people use it. This report can be turned off by setting an environment variable or option.' canonicalUrl: https://grafana.com/docs/k6/latest/set-up/usage-collection/ -redirect: https://grafana.com/docs/k6/latest/set-up/usage-collection/ --- By default, k6 sends a usage report each time it is run, so that we can track how often people use it. This report can be turned off by setting the environment variable `K6_NO_USAGE_REPORT` or by adding the option `--no-usage-report` when executing k6. diff --git a/src/data/markdown/translated-guides/en/08 Misc/02 IntelliSense.md b/src/data/markdown/translated-guides/en/08 Misc/02 IntelliSense.md index 9d7b5fe575..a51672f171 100644 --- a/src/data/markdown/translated-guides/en/08 Misc/02 IntelliSense.md +++ b/src/data/markdown/translated-guides/en/08 Misc/02 IntelliSense.md @@ -2,7 +2,6 @@ title: 'IntelliSense' excerpt: 'k6 has its TypeScript Type Definition that you can configure with your editor to unlock code editing features.' canonicalUrl: https://grafana.com/docs/k6/latest/set-up/configure-k6-intellisense/ -redirect: https://grafana.com/docs/k6/latest/set-up/configure-k6-intellisense/ --- [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense) refers to code editing features like **intelligent code completion** and **quick access to documentation**. These features can significantly improve the developer experience and productivity when working on k6 scripts in your editor of choice. Notable features are: diff --git a/src/data/markdown/translated-guides/en/08 Misc/03 Fine tuning OS.md b/src/data/markdown/translated-guides/en/08 Misc/03 Fine tuning OS.md index 89ce2c9f48..466878185d 100644 --- a/src/data/markdown/translated-guides/en/08 Misc/03 Fine tuning OS.md +++ b/src/data/markdown/translated-guides/en/08 Misc/03 Fine tuning OS.md @@ -2,7 +2,6 @@ title: 'Fine tuning OS' excerpt: 'In this article we will show you how to inspect the OS imposed limits of your system, tweak them and scale for larger tests.' canonicalUrl: https://grafana.com/docs/k6/latest/set-up/fine-tune-os/ -redirect: https://grafana.com/docs/k6/latest/set-up/fine-tune-os/ --- When running large test scripts locally, users sometimes run into limits within their OS that prevent them from making the necessary number of requests to complete the test. diff --git a/src/data/markdown/translated-guides/en/08 Misc/04 k6 REST API.md b/src/data/markdown/translated-guides/en/08 Misc/04 k6 REST API.md index 3eaa928b53..95a40255ba 100644 --- a/src/data/markdown/translated-guides/en/08 Misc/04 k6 REST API.md +++ b/src/data/markdown/translated-guides/en/08 Misc/04 k6 REST API.md @@ -4,8 +4,6 @@ excerpt: 'With this API you can see and control different execution aspects like number of VUs, pause or resume the test, list groups, set and get the setup data and more.' hideFromSidebar: true -canonicalUrl: https://grafana.com/docs/k6/latest/misc/k6-rest-api/ -redirect: https://grafana.com/docs/k6/latest/misc/k6-rest-api/ --- When k6 starts, it spins up an HTTP server with a REST API that can be used to control some diff --git a/src/data/markdown/translated-guides/en/08 Misc/06 Archive.md b/src/data/markdown/translated-guides/en/08 Misc/06 Archive.md index b83e0b766e..200b4ed9ae 100644 --- a/src/data/markdown/translated-guides/en/08 Misc/06 Archive.md +++ b/src/data/markdown/translated-guides/en/08 Misc/06 Archive.md @@ -2,7 +2,6 @@ title: 'Archive Command' excerpt: 'A k6 archive is simply a tar file with all files needed to execute a k6 test.' canonicalUrl: https://grafana.com/docs/k6/latest/misc/archive/ -redirect: https://grafana.com/docs/k6/latest/misc/archive/ --- ## What is an archive? diff --git a/src/data/markdown/translated-guides/en/08 Misc/09 Glossary.md b/src/data/markdown/translated-guides/en/08 Misc/09 Glossary.md index 67fd073c8b..89d79f38ae 100644 --- a/src/data/markdown/translated-guides/en/08 Misc/09 Glossary.md +++ b/src/data/markdown/translated-guides/en/08 Misc/09 Glossary.md @@ -2,7 +2,6 @@ title: Glossary excerpt: 'A list of technical terms commonly used when discussing k6, with definitions.' canonicalUrl: https://grafana.com/docs/k6/latest/misc/glossary/ -redirect: https://grafana.com/docs/k6/latest/misc/glossary/ --- What we talk about when we talk about k6. diff --git a/src/data/markdown/translated-guides/en/Test Types.md b/src/data/markdown/translated-guides/en/Test Types.md index ef2d7bd96e..2d9fc5689a 100644 --- a/src/data/markdown/translated-guides/en/Test Types.md +++ b/src/data/markdown/translated-guides/en/Test Types.md @@ -1,8 +1,7 @@ --- title: 'Test types' excerpt: 'A series of conceptual articles explaining the different types of load tests. Learn about planning, running, and interpreting different tests for different performance goals.' -canonicalUrl: https://grafana.com/load-testing/types-of-load-testing/ -redirect: https://grafana.com/load-testing/types-of-load-testing/ +robots: NOINDEX, FOLLOW # // TODO: Point canonical to new URL once it's published # canonicalUrl: https://grafana.com/ --- diff --git a/src/data/markdown/translated-guides/en/Testing Guides.md b/src/data/markdown/translated-guides/en/Testing Guides.md index 078b54cfab..427a412663 100644 --- a/src/data/markdown/translated-guides/en/Testing Guides.md +++ b/src/data/markdown/translated-guides/en/Testing Guides.md @@ -2,7 +2,6 @@ title: 'Testing guides' excerpt: 'A series of guides to help you defining your load testing strategies.' canonicalUrl: https://grafana.com/docs/k6/latest/testing-guides/ -redirect: https://grafana.com/docs/k6/latest/testing-guides/ --- diff --git a/src/layouts/doc-layout/doc-layout.view.js b/src/layouts/doc-layout/doc-layout.view.js index efb9d7cb35..60e4a887ec 100644 --- a/src/layouts/doc-layout/doc-layout.view.js +++ b/src/layouts/doc-layout/doc-layout.view.js @@ -26,7 +26,7 @@ import { } from 'react-cookie-banner'; import { childrenToList, isInIFrame } from 'utils'; import AlgoliaQueries from 'utils/algolia'; -import { main } from 'utils/urls'; +import { main, app } from 'utils/urls'; import styles from './doc-layout.module.scss'; import ArrowLeft from './svg/arrow-left.inline.svg'; @@ -378,11 +378,8 @@ export const DocLayout = ({ k6.io - - Grafana Cloud k6 + + app.k6.io diff --git a/src/templates/docs/extensions.js b/src/templates/docs/extensions.js index 307f8b0c49..c7bed5cd01 100644 --- a/src/templates/docs/extensions.js +++ b/src/templates/docs/extensions.js @@ -1,12 +1,16 @@ import classNames from 'classnames'; import { + ExtensionsQuickstart, ExtensionsOverview, ExtensionsUseCases, + WhatIsXk6, } from 'components/pages/doc-extensions'; +import TableOfContents from 'components/pages/doc-page/table-of-contents'; import { PageInfo } from 'components/shared/page-info'; import { SEO } from 'components/shared/seo'; import docPageContent from 'components/templates/doc-page/doc-page-content/doc-page-content.module.scss'; import LocaleProvider from 'contexts/locale-provider'; +import { Link } from 'gatsby'; import { useScrollToAnchor } from 'hooks'; import { DocLayout } from 'layouts/doc-layout'; import React, { useRef } from 'react'; @@ -35,9 +39,24 @@ const Extensions = ({ pageContext: { sidebarTree, navLinks } }) => { />
+ + + Next,{' '} + + explore + {' '} + the available extensions to see how you can expand your use of k6 + right now.
+
diff --git a/src/templates/docs/guides.js b/src/templates/docs/guides.js index 5dfe5d185d..bd41628542 100644 --- a/src/templates/docs/guides.js +++ b/src/templates/docs/guides.js @@ -1,8 +1,13 @@ import classNames from 'classnames'; import { DocPageNavigation } from 'components/pages/doc-page/doc-page-navigation'; import TableOfContents from 'components/pages/doc-page/table-of-contents'; -import { WhatIs } from 'components/pages/doc-welcome'; -import { OutdatedBlockquote } from 'components/pages/doc-welcome/outdated-blockquote'; +import { + Features, + Manifesto, + Quickstart, + WhatIs, +} from 'components/pages/doc-welcome'; +import { K6DoesNot } from 'components/pages/doc-welcome/k6-does-not'; import { UseCases } from 'components/pages/doc-welcome/use-cases'; import { PageInfo } from 'components/shared/page-info'; import { SEO } from 'components/shared/seo'; @@ -18,7 +23,8 @@ import { flattenSidebarTree } from 'utils/utils'; const pageInfo = { en: { title: 'Welcome to the k6 documentation', - description: '', + description: + 'This documentation will help you go from a total beginner to a seasoned k6 expert!', }, es: { title: 'Bienvenido a la documentación de k6', @@ -60,9 +66,12 @@ const GuidesContent = ({
- + + + +