{"id":13342842,"url":"https://github.com/szkiba/xk6-g0","last_synced_at":"2025-03-25T12:33:15.097Z","repository":{"id":173729498,"uuid":"651202487","full_name":"szkiba/xk6-g0","owner":"szkiba","description":"Write k6 tests in golang","archived":false,"fork":false,"pushed_at":"2025-02-18T14:45:22.000Z","size":109,"stargazers_count":30,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-20T08:44:59.943Z","etag":null,"topics":["k6-extension","xk6"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/szkiba.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-08T18:21:49.000Z","updated_at":"2025-03-17T16:29:32.000Z","dependencies_parsed_at":"2024-11-14T22:34:01.522Z","dependency_job_id":"a96171a5-ab83-44f6-a005-b8d88148c845","html_url":"https://github.com/szkiba/xk6-g0","commit_stats":null,"previous_names":["szkiba/xk6-g0"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szkiba%2Fxk6-g0","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szkiba%2Fxk6-g0/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szkiba%2Fxk6-g0/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szkiba%2Fxk6-g0/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/szkiba","download_url":"https://codeload.github.com/szkiba/xk6-g0/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245463043,"owners_count":20619601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["k6-extension","xk6"],"created_at":"2024-07-29T19:30:06.090Z","updated_at":"2025-03-25T12:33:14.493Z","avatar_url":"https://github.com/szkiba.png","language":"Go","funding_links":[],"categories":["Extensions"],"sub_categories":["Community"],"readme":"# xk6-g0\n\nWrite k6 tests in golang\n\nThe xk6-g0 extension allows writing k6 tests in the go language.\n\n**script.go**\n\n```go\npackage main\n\nimport \"net/http\"\n\nfunc Default() {\n  http.Get(\"https://test.k6.io\")\n}\n```\n\n**run**\n```bash\n./k6 run script.go\n```\n\nAlthough k6's officially supported scripting language is JavaScript, support for other languages appears from time to time. In this blog post, you can read an understandable and clear explanation of why k6 officially supports only JavaScript language: [Why k6 does not support multiple scripting languages?](https://k6.io/blog/why-k6-does-not-introduce-multiple-scripting-languages/)\n\nxk6-g0 is an experiment to use the go programming language as a full-fledged script language in k6 tests with the support of the community. Since k6 extensions (including xk6-g0) are made in the go language, every xk6-g0 user is also a potential contributor to xk6-g0 development. If the community really wants to use the go programming language to write k6 tests, hopefully they will be committed enough to contribute to xk6-g0 development. Otherwise, xk6-g0 remains an interesting experiment.\n\nWhen using xk6-g0, the tests are executed by a built-in go interpreter ([yaegi](https://github.com/traefik/yaegi)), so there is no need for a compilation or build phase. It is true that the speed of interpreted execution does not reach the speed of compiled code, but it has many advantages. On the other hand, even with JavaScript support, the interpreter performs the tests.\n\nAccepting the [benchmark measurement](https://github.com/d5/tengo#benchmark) made with [tengo](https://github.com/d5/tengo)'s developer, the JavaScript ([goja](https://github.com/dop251/goja)) interpreter calculates Fibonacci numbers twice as fast as the go interpreter ([yaegi](https://github.com/traefik/yaegi)). Well, it is relatively rare to count fibonacci numbers in tests, so we are not far off with the approximation that there is no double multiplier in execution speed. (someday a more accurate measurement would be useful)\n\n## Usage\n\nThe go script should be put in the `main` package. The following lifecycle callback functions and configuration object can be exported by the script:\n  - Setup: corresponds to the [setup function](https://k6.io/docs/using-k6/test-lifecycle/#setup-and-teardown-stages) of the JavaScript API\n  - TearDown: corresponds to the [teardown function](https://k6.io/docs/using-k6/test-lifecycle/#setup-and-teardown-stages) of the JavaScript API\n  - Default: corresponds to the [default export function](https://k6.io/docs/using-k6/test-lifecycle/#the-vu-stage) of the JavaScript API\n  - HandleSummary: corresponds to the [handleSummary function](handlesummary) of the JavaScript\n  - Options: corresponds to the JavaScript API [options object](https://k6.io/docs/using-k6/k6-options/reference/)\n\nThe return values of the lifecycle callback functions are optional, they can also be defined without a return value. The function parameters are also optional, but their order is fixed.\n\nThe script is executed similarly to the JavaScript language:\n\n```bash\n./k6 run scripts/simple/script.go\n```\n\n### Setup\n\n`Setup` function corresponds to the [setup function](https://k6.io/docs/using-k6/test-lifecycle/#setup-and-teardown-stages) of the JavaScript API.\n\n```go\nfunc Setup() (interface{}, error)\n```\n\nThe return values are optional, i.e. in addition to the above form, the following can also be used:\n\n```go\nfunc Setup() interface{}\nfunc Setup() error\nfunc Setup()\n```\n\nOptionally, the following parameters can also be used:\n  - [context.Context](https://pkg.go.dev/context) execution context\n  - [assert.Assertions](https://pkg.go.dev/github.com/stretchr/testify/assert#Assertions) provides assertion methods\n  - [require.Assertions](https://pkg.go.dev/github.com/stretchr/testify/require#Assertions) provides assertion methods\n\n```go\nfunc Setup(context.Context, assert.Assertions) (interface{}, error)\n```\n\n### Teardown\n\n`TearDown` function corresponds to the [teardown function](https://k6.io/docs/using-k6/test-lifecycle/#setup-and-teardown-stages) of the JavaScript API.\n\n```go\nfunc Teardown(data interface{}) error\n```\n\nThe parameter and the return value are optional, i.e. in addition to the above form, the following can also be used:\n\n```go\nfunc Teardown(data interface{})\nfunc Teardown() error\nfunc Teardown()\n```\n\nOptionally, the following parameters can also be used:\n  - [context.Context](https://pkg.go.dev/context) execution context\n  - [assert.Assertions](https://pkg.go.dev/github.com/stretchr/testify/assert#Assertions) provides assertion methods\n  - [require.Assertions](https://pkg.go.dev/github.com/stretchr/testify/require#Assertions) provides assertion methods\n\n```go\nfunc Teardown(ctx context.Context, assert assert.Assertions, data interface{}) error\n```\n\n### Default\n\n`Default` function corresponds to the [default export function](https://k6.io/docs/using-k6/test-lifecycle/#the-vu-stage) of the JavaScript API.\n\n```go\nfunc Default(data interface{}) error\n```\n\nThe parameter and the return value are optional, i.e. in addition to the above form, the following can also be used:\n\n```go\nfunc Default(data interface{})\nfunc Default() error\nfunc Default()\n```\n\nOptionally, the following parameters can also be used:\n  - [context.Context](https://pkg.go.dev/context) execution context\n  - [assert.Assertions](https://pkg.go.dev/github.com/stretchr/testify/assert#Assertions) provides assertion methods\n  - [require.Assertions](https://pkg.go.dev/github.com/stretchr/testify/require#Assertions) provides assertion methods\n\n```go\nfunc Default(ctx context.Context, assert assert.Assertions, data interface{}) error\n```\n\n### HandleSummary\n\n`HandleSummary` function corresponds to the [handleSummary function](handlesummary) of the JavaScript.\n\n```go\nfunc HandleSummary(data map[string]interface{}) (map[string]interface{}, error)\n```\n\nThe error return value is optional, i.e. in addition to the above form, the following can also be used:\n\n```go\nfunc HandleSummary(data map[string]interface{}) map[string]interface{}\n```\n\n### Options\n\n`Options` variable corresponds to the JavaScript API [options object](https://k6.io/docs/using-k6/k6-options/reference/).\n\n```go\nvar Options map[string]interface{}\n```\n\n## Roadmap\n\nThe xk6-g0 is currently in Proof of Concept status. The further fate of the development depends on the community's feedback on the usefulness of the concept.\n\n**Is it useful to support the go language (yaegi interpreter) in k6 tests?**\nYou can vote here: https://github.com/szkiba/xk6-g0/discussions/1\n\n## API\n\n**The primary API design consideration: don't have an API at all.**\n\nThere are many popular packages for the go programming language, xk6-g0 tries to implement the necessary functionality by integrating and supporting these packages without its own API. This approach has many advantages, such as:\n\n  - the test writer does not need to learn a new API\n  - test scripts can be tested using standard go testing\n\nIn addition to the go standard library, the following third-party packages can be used:\n\n  - https://github.com/go-resty/resty\n  - https://github.com/sirupsen/logrus\n  - https://github.com/stretchr/testify\n  - https://github.com/PuerkitoBio/goquery\n  - https://github.com/tidwall/gjson\n  - https://github.com/PaesslerAG/jsonpath\n  - https://github.com/santhosh-tekuri/jsonschema/v5\n  - https://github.com/brianvoe/gofakeit/v6\n\n\n### Checks\n\nThe `Default` function's optional [assert.Assertions](https://pkg.go.dev/github.com/stretchr/testify/assert#Assertions) or [require.Assertions](https://pkg.go.dev/github.com/stretchr/testify/require#Assertions) parameters can be used to define the [k6 checks](https://k6.io/docs/using-k6/checks/). The name of the check will be the message parameter of the corresponding assertion function.\n\nOf course, metrics are also created from the checks defined in this way.\n\n```go\npackage main\n\nimport (\n  \"net/http\"\n\n  \"github.com/stretchr/testify/assert\"\n)\n\nfunc Default(assert *assert.Assertions) {\n  res, err := http.Get(\"https://httpbin.test.k6.io/get\")\n\n  assert.NoError(err, \"got response without error\")\n  assert.Equal(http.StatusOK, res.StatusCode, \"status code was 200\")\n  assert.Equal(\"application/json\", res.Header.Get(\"Content-Type\"), \"content type was application/json\")\n}\n```\n\n**output**\n\n```plain\n\n          /\\      |‾‾| /‾‾/   /‾‾/   \n     /\\  /  \\     |  |/  /   /  /    \n    /  \\/    \\    |     (   /   ‾‾\\  \n   /          \\   |  |\\  \\ |  (‾)  | \n  / __________ \\  |__| \\__\\ \\_____/ .io\n\n  execution: local\n     script: -\n     output: -\n\n  scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):\n           * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)\n\n\n     ✓ got response without error\n     ✓ status code was 200\n     ✓ content type was application/json\n\n     checks.....................: 100.00% ✓ 3        ✗ 0\n     data_received..............: 6.0 kB  14 kB/s\n     data_sent..................: 457 B   1.1 kB/s\n     http_req_blocked...........: avg=302.7ms  min=302.7ms  med=302.7ms  max=302.7ms  p(90)=302.7ms  p(95)=302.7ms \n     http_req_connecting........: avg=124.32ms min=124.32ms med=124.32ms max=124.32ms p(90)=124.32ms p(95)=124.32ms\n     http_req_duration..........: avg=126.6ms  min=126.6ms  med=126.6ms  max=126.6ms  p(90)=126.6ms  p(95)=126.6ms \n     http_req_receiving.........: avg=355.31µs min=355.31µs med=355.31µs max=355.31µs p(90)=355.31µs p(95)=355.31µs\n     http_req_sending...........: avg=54.2µs   min=54.2µs   med=54.2µs   max=54.2µs   p(90)=54.2µs   p(95)=54.2µs  \n     http_req_tls_handshaking...: avg=151.39ms min=151.39ms med=151.39ms max=151.39ms p(90)=151.39ms p(95)=151.39ms\n     http_req_waiting...........: avg=126.19ms min=126.19ms med=126.19ms max=126.19ms p(90)=126.19ms p(95)=126.19ms\n     http_reqs..................: 1       2.326236/s\n     iteration_duration.........: avg=429.68ms min=429.68ms med=429.68ms max=429.68ms p(90)=429.68ms p(95)=429.68ms\n     iterations.................: 1       2.326236/s\n```\n\n### HTTP client\n\nFrom the http package of the standard library, metrics are created on the use of the following:\n\n- http.DefaultClient\n- http.Get, http.Head, http.Post, http.PostForm\n\nIn addition, the https://github.com/go-resty/resty HTTP client can also be used, metrics are generated from its use.\n\n```go\npackage main\n\nimport \"github.com/go-resty/resty/v2\"\n\nfunc Default() error {\n  _, err := client.R().Get(\"https://httpbin.test.k6.io/get\")\n\n  return err\n}\n\nvar client *resty.Client\n\nfunc init() {\n  client = resty.New()\n}\n```\n\n### HTML\n\nHTML documents can be parsed and manipulated using the popular [github.com/PuerkitoBio/goquery](https://github.com/PuerkitoBio/goquery) package, which brings a syntax and a set of features similar to jQuery to the Go language.\n\n```go\npackage main\n\nimport (\n  \"github.com/PuerkitoBio/goquery\"\n  \"github.com/sirupsen/logrus\"\n)\n\nfunc Default() error {\n  doc, err := goquery.NewDocument(\"https://test.k6.io\")\n  if err != nil {\n    return err\n  }\n\n  logrus.Info(doc.Find(\"h1.title span.text-blue\").Text())\n\n  return nil\n}\n```\n\n### JSON\n\nThe [gjson](https://github.com/tidwall/gjson) and [jsonpath](github.com/PaesslerAG/jsonpath) packages can be used to query JSON documents.\n\n**gjson**\n```go\npackage main\n\nimport (\n  \"net/http\"\n\n  \"github.com/go-resty/resty/v2\"\n  \"github.com/stretchr/testify/require\"\n  \"github.com/tidwall/gjson\"\n)\n\nfunc Default(require *require.Assertions) {\n  res, err := resty.New().R().Get(\"https://httpbin.test.k6.io/get\")\n\n  require.NoError(err, \"request success\")\n  require.Equal(http.StatusOK, res.StatusCode(), \"status code 200\")\n\n  body := res.Body()\n\n  val := gjson.GetBytes(body, \"headers.Host\").Str\n\n  require.Equal(\"httpbin.test.k6.io\", val, \"headers.Host value OK\")\n}\n```\n\n**jsonpath**\n```go\npackage main\n\nimport (\n  \"net/http\"\n\n  \"github.com/PaesslerAG/jsonpath\"\n  \"github.com/go-resty/resty/v2\"\n  \"github.com/stretchr/testify/require\"\n)\n\nfunc Default(require *require.Assertions) {\n  body := make(map[string]interface{})\n  res, err := resty.New().R().SetResult(\u0026body).Get(\"https://httpbin.test.k6.io/get\")\n\n  require.NoError(err, \"request success\")\n  require.Equal(http.StatusOK, res.StatusCode(), \"status code 200\")\n\n  val, err := jsonpath.Get(\"$.headers.Host\", body)\n\n  require.NoError(err, \"$.headers.Host no error\")\n  require.Equal(\"httpbin.test.k6.io\", val, \"$.headers.Host value OK\")\n}\n```\n\n### Logging\n\nThe https://github.com/sirupsen/logrus package can be used for logging in the test script.\n\n```go\npackage main\n\nimport \"github.com/sirupsen/logrus\"\n\nfunc Setup() interface{} {\n  logrus.Info(\"Setup\")\n\n  return map[string]interface{}{\n    \"foo\": \"bar\",\n  }\n}\n\nfunc Default(data interface{}) {\n  logrus.Info(\"Default\", data)\n}\n\nfunc Teardown(data interface{}) {\n  logrus.Info(\"Teardown\", data)\n}\n\nfunc init() {\n  logrus.Info(\"init\")\n}\n```\n\n### Context\n\nThe first parameter of the `Default` function is optionally a [context.Context](https://pkg.go.dev/context). This can be used to perform context aware operations and to access various context variables.\n\nThe usual k6 variables (eg `__VU`, `__ENV`, `__ITER`) and the variables of the `k6/execution` module can be accessed using the `Value` function of the context parameter.\n\n```go\npackage main\n\nimport (\n  \"context\"\n\n  \"github.com/sirupsen/logrus\"\n)\n\nfunc Default(ctx context.Context) {\n  vu := ctx.Value(\"__VU\").(int64)\n  env := ctx.Value(\"__ENV\").(map[string]string)\n  iter := ctx.Value(\"__ITER\").(int64)\n\n  logrus.Info(vu)\n  logrus.Info(iter)\n  logrus.Info(env[\"PATH\"])\n  logrus.Info(ctx.Value(\"execution.scenario.name\"))\n}\n```\n\n## Download\n\nYou can download pre-built k6 binaries from [Releases](https://github.com/szkiba/xk6-g0/releases/) page. Check [Packages](https://github.com/szkiba/xk6-g0/pkgs/container/xk6-g0) page for pre-built k6 Docker images.\n\n## Build\n\nYou can build the k6 binary on various platforms, each with its requirements. The following shows how to build k6 binary with this extension on GNU/Linux distributions.\n\n### Prerequisites\n\nYou must have the latest Go version installed to build the k6 binary. The latest version should match [k6](https://github.com/grafana/k6#build-from-source) and [xk6](https://github.com/grafana/xk6#requirements).\n\n- [Git](https://git-scm.com/) for cloning the project\n- [xk6](https://github.com/grafana/xk6) for building k6 binary with extensions\n\n### Install and build the latest tagged version\n\n1. Install `xk6`:\n\n   ```shell\n   go install go.k6.io/xk6/cmd/xk6@latest\n   ```\n\n2. Build the binary:\n\n   ```shell\n   xk6 build --with github.com/szkiba/xk6-g0@latest\n   ```\n\n\u003e **Note**\n\u003e You can always use the latest version of k6 to build the extension, but the earliest version of k6 that supports extensions via xk6 is v0.43.1. The xk6 is constantly evolving, so some APIs may not be backward compatible.\n\n### Build for development\n\nIf you want to add a feature or make a fix, clone the project and build it using the following commands. The xk6 will force the build to use the local clone instead of fetching the latest version from the repository. This process enables you to update the code and test it locally.\n\n```bash\ngit clone git@github.com:szkiba/xk6-g0.git \u0026\u0026 cd xk6-g0\nxk6 build --with github.com/szkiba/xk6-g0@latest=.\n```\n\n## Docker\n\nYou can also use pre-built k6 image within a Docker container. In order to do that, you will need to execute something like the following:\n\n**Linux**\n\n```plain\ndocker run -v $(pwd):/work -it --rm ghcr.io/szkiba/xk6-g0:latest run /work/scripts/simple/script.go\n```\n\n**Windows**\n\n```plain\ndocker run -v %cd%:/work -it --rm ghcr.io/szkiba/xk6-g0:latest run /work/scripts/simple/script.go\n```\n\n## Example scripts\n\nThere are many examples in the [scripts](https://github.com/szkiba/xk6-g0/tree/master/scripts) directory that show how to use various features of the extension.\n\n## Extending xk6-g0\n\nxk6-g0 allows you to install additional packages in addition to the built-in go packages without changing the xk6-g0 source code. For this, for example, a function must be registered from the init() function of a custom k6 extension, which can be used to make additional packages available.\n\nCheck [xk6-g0-figure](https://github.com/szkiba/xk6-g0-figure) as an example addon.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fszkiba%2Fxk6-g0","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fszkiba%2Fxk6-g0","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fszkiba%2Fxk6-g0/lists"}