Coder Social home page Coder Social logo

k6x's Introduction

GitHub Release Go Report Card GitHub Actions codecov GitHub Downloads

Important

The k6x is under refactor. This documentation is about the refactored code. Previous documentation is marked with the before-grafana git tag. The last release before the refactor is v0.4.0.

k6x

Run k6 with extensions

Synopsis

Run k6 with a seamless extension user experience.

k6x is a k6 launcher that automatically provides k6 with the extensions used by the test. In order to do this, it analyzes the script arguments of the run and archive subcommands, detects the extensions to be used and their version constraints.

The launcher acts as a drop-in replacement for the k6 command. For more convenient use, it is advisable to create an alias or shell script called k6 for the launcher. The alias can be used in exactly the same way as the k6 command, with the difference that it generates the real k6 on the fly based on the extensions you want to use.

Any k6 command can be used. Use the help command to list the available k6 commands.

Since k6x tries to emulate the k6 command line, the help command or the --help flag cannot be used to display help from k6x command itself. The k6x help can be displayed using the --usage flag:

k6x --usage

Prerequisites

k6x tries to provide the appropriate k6 executable after detecting the extension dependencies. This can be done using a build service or a native builder.

Build Service

No additional installation is required to use the build service, just provide the build service URL.

The build service URL can be specified in the K6_BUILD_SERVICE_URL environment variable or by using the --build-service-url flag.

There is no default URL for the build service, otherwise k6x will automatically provide k6 with the native builder.

Native Builder

To use the native builder, you only need to install the Go language toolkit.

The native builder uses a k6 extension catalog to resolve extension URLs and versions. The extension catalog URL has a default value. A different extension catalog URL can be specified in the K6_EXTENSION_CATALOG_URL environment variable or by using the --extension-catalog-url flag.

Pragma

Version constraints can be specified using the JavaScript "use ..." pragma syntax for k6 and extensions. Put the following lines at the beginning of the test script:

"use k6 >= v0.52";
"use k6 with k6/x/faker > 0.2";

Any number of "use k6" pragmas can be used.

Note The use of pragmas is completely optional for JavaScript type extensions, it is only necessary if you want to specify version constraints.

The pragma syntax can also be used to specify an extension dependency that is not referenced in an import expression. A typical example of this is the Output type extension such as xk6-top:

"use k6 with top >= 0.1";

Read the version constraints syntax in the Version Constraints section

Environment

The extensions to be used and optionally their version constraints can also be specified in the K6_DEPENDENCIES environment variable. The value of the environment variable K6_DEPENDENCIES is a list of elements separated by semicolons. Each element specifies an extension (or k6 itself) and optionally its version constraint.

k6>=0.52;k6/x/faker>=0.3;k6/x/sql>=0.4

Manifest

The manifest file is a JSON file, the dependencies property of which can specify extension dependencies and version constraints. The value of the dependencies property is a JSON object. The property names of this object are the extension names (or k6) and the values ​​are the version constraints.

{
  "dependencies": {
    "k6": ">=0.52",
    "k6/x/faker": ">=0.3",
    "k6/x/sql": ">=0.4"
  }
}

The manifest file is a file named package.json, which is located closest to the k6 test script or the current directory, depending on whether the given subcommand has a test script argument (e.g. run, archive) or not (e.g. version). The package.json file is searched for up to the root of the directory hierarchy.

Limitations

Version constraints can be specified in several sources (pragma, environment, manifest) but cannot be overwritten. That is, for a given extension, the version constraints from different sources must either be equal, or only one source can contain a version constraint.

Version Constraints

This section is based on the Masterminds/semver documentation.

Basic Comparisons

There are two elements to the comparisons. First, a comparison string is a list of space or comma separated AND comparisons. These are then separated by || (OR) comparisons. For example, ">= 1.2 < 3.0.0 || >= 4.2.3" is looking for a comparison that's greater than or equal to 1.2 and less than 3.0.0 or is greater than or equal to 4.2.3.

The basic comparisons are:

  • =: equal (aliased to no operator)
  • !=: not equal
  • >: greater than
  • <: less than
  • >=: greater than or equal to
  • <=: less than or equal to

Hyphen Range Comparisons

There are multiple methods to handle ranges and the first is hyphens ranges. These look like:

  • 1.2 - 1.4.5 which is equivalent to >= 1.2 <= 1.4.5
  • 2.3.4 - 4.5 which is equivalent to >= 2.3.4 <= 4.5

Wildcards In Comparisons

The x, X, and * characters can be used as a wildcard character. This works for all comparison operators. When used on the = operator it falls back to the patch level comparison (see tilde below). For example,

  • 1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • >= 1.2.x is equivalent to >= 1.2.0
  • <= 2.x is equivalent to < 3
  • * is equivalent to >= 0.0.0

Tilde Range Comparisons (Patch)

The tilde (~) comparison operator is for patch level ranges when a minor version is specified and major level changes when the minor number is missing. For example,

  • ~1.2.3 is equivalent to >= 1.2.3, < 1.3.0
  • ~1 is equivalent to >= 1, < 2
  • ~2.3 is equivalent to >= 2.3, < 2.4
  • ~1.2.x is equivalent to >= 1.2.0, < 1.3.0
  • ~1.x is equivalent to >= 1, < 2

Caret Range Comparisons (Major)

The caret (^) comparison operator is for major level changes once a stable (1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts as the API stability level. This is useful when comparisons of API versions as a major change is API breaking. For example,

  • ^1.2.3 is equivalent to >= 1.2.3, < 2.0.0
  • ^1.2.x is equivalent to >= 1.2.0, < 2.0.0
  • ^2.3 is equivalent to >= 2.3, < 3
  • ^2.x is equivalent to >= 2.0.0, < 3
  • ^0.2.3 is equivalent to >=0.2.3 <0.3.0
  • ^0.2 is equivalent to >=0.2.0 <0.3.0
  • ^0.0.3 is equivalent to >=0.0.3 <0.0.4
  • ^0.0 is equivalent to >=0.0.0 <0.1.0
  • ^0 is equivalent to >=0.0.0 <1.0.0
k6x [flags] [command]

Flags

      --build-service-url string       URL of the k6 build service to be used
      --extension-catalog-url string   URL of the k6 extension catalog to be used
  -h, --help                           help for k6
      --no-color                       disable colored output
  -q, --quiet                          disable progress updates
      --usage                          print launcher usage
  -v, --verbose                        enable verbose logging

Example

k6x run script.js

That's all!

script.js
import { Faker } from "k6/x/faker";
import sql from "k6/x/sql";

const db = sql.open("sqlite3", "./test-users.db");

export function setup() {
  db.exec(`
  CREATE TABLE IF NOT EXISTS users (
    sub varchar PRIMARY KEY,
    name varchar NOT NULL,
    email varchar NOT NULL
  );`);

  const faker = new Faker(11);

  db.exec(`
    INSERT OR REPLACE INTO users (sub, name, email) VALUES (
      '${faker.internet.username()}',
      '${faker.person.firstName()} ${faker.person.lastName()}',
      '${faker.person.email()}'
    );`);
}

export function teardown() {
  db.close();
}

export default function () {
  const results = sql.query(db, "SELECT * FROM users");

  for (const row of results) {
    const { sub, name, email } = row;

    console.log({ sub, name, email });
  }
}

Install

Precompiled binaries can be downloaded and installed from the Releases page.

If you have a go development environment, the installation can also be done with the following command:

go install github.com/grafana/k6x@latest

The launcher acts as a drop-in replacement for the k6 command. For more convenient use, it is advisable to create an alias or shell script called k6 for the launcher. The alias can be used in exactly the same way as the k6 command, with the difference that it generates the real k6 on the fly based on the extensions you want to use.

Contributing

If you want to contribute, please read the CONTRIBUTING.md file.

Tasks

This section contains a description of the tasks performed during development. Commands must be issued in the repository base directory. If you have the xc command-line tool, individual tasks can be executed simply by using the xc task-name command in the repository base directory.

Click to expand

readme

Update documentation in README.md.

go run ./tools/gendoc README.md

lint

Run the static analyzer.

We make use of the golangci-lint tool to lint the code in CI. The actual version you can find in our .golangci.yml.

golangci-lint run

test

Run the tests.

To exercise the entire test suite, please run the following command

go test -count 1 -race -coverprofile=build/coverage.txt ./...

coverage

View the test coverage report.

go tool cover -html=build/coverage.txt

build

Build the executable binary.

This is the easiest way to create an executable binary (although the release process uses the goreleaser tool to create release versions).

go build -ldflags="-w -s" -o k6x .

snapshot

Creating an executable binary with a snapshot version.

The goreleaser command-line tool is used during the release process. During development, it is advisable to create binaries with the same tool from time to time.

goreleaser build --snapshot --clean --single-target -o k6x

docker

Building a Docker image. Before building the image, it is advisable to perform a snapshot build using goreleaser. To build the image, it is advisable to use the same Docker.goreleaser file that goreleaser uses during release.

Requires: snapshot

docker build -t grafana/k6x -f Dockerfile.goreleaser .

examples

Run all scripts in the examples directory with a fresh build.

Requires: clean, snapshot

find  examples -type f | xargs -n 1 ./k6x run

clean

Delete the build directory.

rm -rf build

k6x's People

Contributors

balazs-andorko-nng avatar bandorko avatar dependabot[bot] avatar szkiba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

k6x's Issues

Docker image does not support running browser tests

Brief summary

When running a test script that imports the browser experimental extension the test fails because the browser binary is not present in the image. As the browser is an experimental feature already integrated into k6, this should be supported by default.

k6 version

0.46

xk6-dashboard version

v0.4.0

OS

Linux

Docker version and image (if applicable)

No response

Steps to reproduce the problem

Create this test script localy as browser.js

import { browser } from 'k6/experimental/browser';

export const options = {
  scenarios: {
    ui: {
      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();
  }
}

Launch k6x image with the following command:

docker run -it  --mount type=bind,src=$PWD/browser.js,dst=/home/k6x/browser.js  szkiba/k6x:v0.4.0 run browser.js

Expected behaviour

The test runs successfully

Actual behaviour

Error message

ERRO[0001] error building browser on IterStart: launching browser: exec: no command at file:///home/k6x/browser.js:16:15(0)

Filter extension registry

Feature Description

In certain runtime environments, the use of arbitrary extensions is not allowed. There is a need to limit the extensions that can be used.

Suggested Solution (optional)

This use case can be solved most flexibly by narrowing down the extension registry. The content of the extension registry can be narrowed using a jmespath syntax filter expression. Extensions can be filtered based on any property.

allow only officially supported extensions

k6x --filter "[?contains(tiers,'Official')]" run script.js

allow only cloud enabled extensions

k6x --filter "[?cloudEnabled == true]" run script.js

Already existing or connected issues / PRs (optional)

No response

Create and publish docker image

In certain circumstances, it can be useful to run k6x using the docker engine itself, as a drop-in replacement of the k6 docker image. Therefore, it is advisable to publish in the form of a docker image that contains the tools necessary for building (golang, git).

In addition, the k6x docker image can be used instead of the xk6 docker image for building, which allows for faster builds. The go cache (go build, go module) can be placed on a separate /cache volume, so it can easily be made persistent.

Capability to include extension from source on the local machine

First of all: I realy like this project. Thx @szkiba

I am experimenting with it, and try to combine with xk6-g0 to write load test in go. It would be really useful, if I could overwrite an automatically discovered extension (e.g.: when I try to modify something on xk6-g0) or if I could include an officially not supported (not in the k6 extension registry) extension.
Due to lack of this option, I had to fallback to xk6.

Import constraints

Import constraints

Import constraints allow you to control the module names allowed in import (and require) expressions. Disabled imports are ignored by k6x during processing. That is, the disabled modules will not be crawled (in the case of JavaScript modules) or will not be included in the k6 binary (in the case of extension modules).

The general form of import constraints:

"use k6 import allow|deny globlist";

Where globlist is a space-separated list of well-known glob patterns (?,*,**, etc.).

By default, any module name is allowed. Import constraints are evaluated in the order of declaration. The evaluation stops at the first pattern match. If there was no pattern match, the given module will be enabled.

The following example disables all extensions except the k6/x/faker and k6/x/mock extensions:

"use k6 import allow k6/x/faker k6/x/mock";
"use k6 import deny k6/x/**";

Disable modules

Disabling modules is possible using the "use k6 import deny globlist" pragma. For example, to disable all extensions:

"use k6 import deny k6/x/**";

Enable modules

Modules can be enabled using the "use k6 import allow globlist" pragma. For example, enabling the faker extension:

"use k6 import allow k6/x/faker";

Add dependencies on the command line

Feature Description

In some cases, it may be useful to add dependencies on the command line without modifying the test script.

Suggested Solution (optional)

Additional dependencies and version constraints can be specified on the command line with the --with flag.

--with dependency you can specify additional dependencies and version constraints, the form of the dependency is the same as that used in the "use k6 with" pragma (practically the same as the string after the use k6 with)

k6x run --with k6/x/mock script.js

The example above adds the xk6-mock extension to the list of dependencies.

Already existing or connected issues / PRs (optional)

This feature is a simplified version of #8, making it obsolete.

Add --with option to specify extensions to build

In some cases, it would be desirable to allow the user to specify the extensions that should be built into the binary produced by k6x:

  1. With the build subcommand, for building a custom binary to be used with multiple tests (similar to using xk6)
k6x build --with=github.com/grafana/xk6-disruptor
  1. With the run subcommand, to allow specifying the version of the extensions without having to modify the code
k6x --with=github.com/grafana/[email protected]  run test.js
  1. With the run subcommand, when we want to ensure only a set of pre-approved extensions can be used and prevent the user from using other extensions in their tests (accidentally or maliciously)
k6x  --with=github.com/grafana/xk6-disruptor run test.js

Cases 1 and 3 require disabling the automatic dependency discovery. In the case of the build subcommand, the test script does not need to be provided.

In case 2 it could still be valid to combine information from the --with argument with the discovery of dependencies, but this creates some complexity in the CLI interface, so we suggest disabling auto-discovery when the with option is specified.

Build various Docker images

It is advisable to build Docker images with different contents and sizes for different use cases.

Suffix Features Includes
-with-go browser API
service builder
native builder
k6x
Chromium
go toolkit
git
-with-browser browser API
service builder
k6x
Chromium
  service builder k6x

Refactoring k6x based on the new libraries

Refactoring k6x based on the new libraries

In the meantime, the k6x logic was moved to the following new libraries:

  • k6catalog
  • k6build
  • k6deps
  • k6exec

From now on, k6x will be a command-line tool integrating the above libraries.

Using Unregistered Extensions

Feature Description

Proprietary extensions are usually not registered in the extension registry. Their use would be made possible by supporting the use of unregistered extensions.

Suggested Solution (optional)

New --register flag:

--register name=path use unregistered extension, where name is the name of the extension and path is the module path. It implies the use of the native builder (--builder native)

k6x --register k6/x/foo=github.com/org/foo run script.js

Output extensions not detected in CLI

Brief summary

When providing -o output-prometheus-pushgateway flag same output as with out-of-the-box k6 is received.

k6 version

v0.49.0

xk6-dashboard version

N/A

OS

macOS 14.2.1 (23C71)

Docker version and image (if applicable)

szkiba/k6x

Steps to reproduce the problem

@ type of preconditions were tested:

  1. Gitlab CI with image: szkiba/k6x
  2. Local install of go install github.com/szkiba/k6x@latest and even go install github.com/szkiba/k6x@latest --with github.com/martymarron/xk6-output-prometheus-pushgateway@latest

Run a script with -o output-prometheus-pushgateway flag. E.g:
k6x run dist/discovery/temp-test.js -o output-prometheus-pushgateway
or
k6x run -o output-prometheus-pushgateway dist/discovery/temp-test.js

P.S. If I run ./k6 run dist/discovery/temp-test.js -o output-prometheus-pushgateway after generating a binary locally using the bundle builder: xk6 build v0.49.0 --with github.com/martymarron/xk6-output-prometheus-pushgateway it works as expected.

Expected behaviour

Output extension is detected from command line and necessary package is involved

Actual behaviour

time="2024-02-07T09:44:24Z" level=error msg="invalid output type 'output-prometheus-pushgateway', available types are: cloud, csv, experimental-prometheus-rw, influxdb, json, statsd, web-dashboard"

Using pragmas on the command line

Using pragmas on the command line

In some cases, it may be useful to specify the "use k6 ..." pragma on the command line. For example, additional pragmas can be specified for a specific test run without modifying the test script.

The --use option can be used to specify pragmas on the command line.

Usage:

--use pragma specifying the use k6 ... pragma to be evaluated before the test script (can be used multiple times), where pragma is a k6x pragma without the use k6 prefix

k6x run --use "import allow k6/x/mock" --use "import deny k6/x/**" script.js

The above example disables the processing of all other extensions except k6/x/mock

Allow overriding the location of the build cache

Enhancement Description

Add a flag such as --cache to allow overriding the location of the build cache.

Suggested Solution (optional)

No response

Already existing or connected issues / PRs (optional)

No response

Builder Service

Builder Service

The k6x builder service is an HTTP service that generates a k6 binary with the extensions specified in the request. The service is included in the k6x binary, so it can be started using the k6x service command.

The k6x builder service can be used independently, from the command line (e.g. using curl or wget commands), from a web browser, or from different subcommands of the k6x launcher as a builder called service.

Usage from the command line

The k6 binary can be easily built using wget , curl or other command-line http client by retrieving the appropriate builder service URL:

using wget

wget --content-disposition https://example.com/linux/amd64/[email protected],[email protected],k6/x/[email protected],[email protected]

using curl

curl -OJ https://example.com/linux/amd64/[email protected],[email protected],k6/x/[email protected],[email protected]

Usage from k6x

The builder service can be used from k6x using the --builder service flag:

k6x run --builder service script.js

k6x expects the address of the builder service in the environment variable called K6X_BUILDER_SERVICE. There is currently no default, it must be specified.

Simplified command line usage

In order to simplify use from the command line, the service also accepts version dependencies in any order. In this case, after unlocking the latest versions and sorting, the response will be an HTTP redirect.

using wget

wget --content-disposition https://example.com/linux/amd64/top,k6/x/faker,dashboard

using curl

curl -OJL https://example.com/linux/amd64/top,k6/x/faker,dashboard

How It Works

The service serves HTTP GET requests, with a well-defined path structure:

htps://example.com/goos/goarch/dependency-list

Where goos is the usual operating system name in the go language (e.g. linux, windows, darwin), goarch is the usual processor architecture in the go language (e.g. amd64, arm64). The dependency-list is a comma-separated list of dependencies, in the following form:

name@version

Where name is the name of the dependency and version is the version number according to semver (with an optional leading v character). The first item in the list is always the dependency named k6, and the other items are sorted alphabetically by name. For example:

Based on the platform parameters (goos, goarch) and dependencies, the service prepares the k6 binary.

Since the response (the k6 binary) depends only on the request path, it can be easily cached. The service therefore sets a sufficiently long caching period (at least three month) in the response, as well as the usual cache headers (e.g. ETag). By placing a caching proxy in front of the service, it can be ensured that the actual k6 binary build takes place only once for each parameter combination.

The advantage of the solution is that the k6 binary is created on the fly, only for the parameter combinations that are actually used. Since the service preserves the go cache between builds, a specific build happens quickly enough.

Module replacement feature

Feature Description

In some cases, it can be useful to use another path instead of the module path registered in the extension registry. For example, using a forked repository, or using a local file-system path in the case of a native builder. These use cases would be solved by the module replacement feature.

Suggested Solution

New --replace flag:

--replace name=path replaces the module path, where name is the dependency/module name and path is a remote module path (version should be appended with @) or an absolute local file-system path (a path starting with . can also be used, which will be resolved to an absolute path). It implies the use of the native builder (--builder native) and clean flag (--clean)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.