Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Adding k6 module #8318

Merged
merged 8 commits into from Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Expand Up @@ -30,6 +30,7 @@ body:
- HiveMQ
- InfluxDB
- K3S
- K6
- Kafka
- LocalStack
- MariaDB
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/enhancement.yaml
Expand Up @@ -30,6 +30,7 @@ body:
- HiveMQ
- InfluxDB
- K3S
- K6
- Kafka
- LocalStack
- MariaDB
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature.yaml
Expand Up @@ -30,6 +30,7 @@ body:
- HiveMQ
- InfluxDB
- K3S
- K6
- Kafka
- LocalStack
- MariaDB
Expand Down
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Expand Up @@ -148,6 +148,14 @@ updates:
ignore:
- dependency-name: "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml"
update-types: [ "version-update:semver-minor", "version-update:semver-patch" ]
- package-ecosystem: "gradle"
directory: "/modules/k6"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
ignore:
- dependency-name: "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml"
update-types: [ "version-update:semver-minor", "version-update:semver-patch" ]
- package-ecosystem: "gradle"
directory: "/modules/kafka"
schedule:
Expand Down
4 changes: 4 additions & 0 deletions .github/labeler.yml
Expand Up @@ -87,6 +87,10 @@
- changed-files:
- any-glob-to-any-file:
- modules/k3s/**/*
"modules/k6":
- changed-files:
- any-glob-to-any-file:
- modules/k6/**/*
"modules/kafka":
- changed-files:
- any-glob-to-any-file:
Expand Down
39 changes: 39 additions & 0 deletions docs/modules/k6.md
@@ -0,0 +1,39 @@
# k6 Module

!!! note
This module is INCUBATING.
While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future.
See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy.

Testcontainers module for [k6](https://registry.hub.docker.com/r/grafana/k6).

[k6](https://k6.io/) is an extensible reliability testing tool built for developer happiness.
javaducky marked this conversation as resolved.
Show resolved Hide resolved

## Basic script execution

Execute a simple k6 test script, `test.js`, with commandline options and injected script variable.

Create a simple k6 test script to be executed as part of your tests:

<!--codeinclude-->
[Setup the container](../../modules/k6/src/test/java/org/testcontainers/k6/K6ContainerTests.java) inside_block:standard_k6
[Content of `scripts/test.js`](../../modules/k6/src/test/resources/scripts/test.js) inside_block:access_script_vars
<!--/codeinclude-->

## Adding this module to your project dependencies

Add the following dependency to your `pom.xml`/`build.gradle` file:

=== "Gradle"
```groovy
testImplementation "org.testcontainers:k6:{{latest_version}}"
```
=== "Maven"
```xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>k6</artifactId>
<version>{{latest_version}}</version>
<scope>test</scope>
</dependency>
```
1 change: 1 addition & 0 deletions mkdocs.yml
Expand Up @@ -82,6 +82,7 @@ nav:
- modules/gcloud.md
- modules/hivemq.md
- modules/k3s.md
- modules/k6.md
- modules/kafka.md
- modules/localstack.md
- modules/milvus.md
Expand Down
7 changes: 7 additions & 0 deletions modules/k6/build.gradle
@@ -0,0 +1,7 @@
description = "Testcontainers :: k6"
eddumelendez marked this conversation as resolved.
Show resolved Hide resolved

dependencies {
api project(':testcontainers')

testImplementation 'org.assertj:assertj-core:3.25.2'
}
89 changes: 89 additions & 0 deletions modules/k6/src/main/java/org/testcontainers/k6/K6Container.java
@@ -0,0 +1,89 @@
package org.testcontainers.k6;

import org.apache.commons.io.FilenameUtils;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class K6Container extends GenericContainer<K6Container> {
eddumelendez marked this conversation as resolved.
Show resolved Hide resolved

/** Standard image for k6, as provided by Grafana. */
private static final DockerImageName K6_IMAGE = DockerImageName.parse("grafana/k6");

private String testScript;

private List<String> cmdOptions = new ArrayList<>();

private Map<String, String> scriptVars = new HashMap<>();

/**
* Creates a new container instance based upon the provided image name.
*/
public K6Container(String dockerImageName) {
this(DockerImageName.parse(dockerImageName));
}

/**
* Creates a new container instance based upon the provided image.
*/
public K6Container(DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(K6_IMAGE);
}

/**
* Specifies the test script to be executed within the container.
* @param testScript file to be copied into the container
* @return the builder
*/
public K6Container withTestScript(MountableFile testScript) {
this.testScript = "/home/k6/" + FilenameUtils.getName(testScript.getResolvedPath());
withCopyFileToContainer(testScript, this.testScript);
return self();
}

/**
* Specifies additional command line options to be provided to the k6 command.
* @param options command line options
* @return the builder
*/
public K6Container withCmdOptions(String... options) {
cmdOptions.addAll(Arrays.asList(options));
return self();
}

/**
* Adds a key-value pair for access within test scripts as an environment variable.
* @param key unique identifier for the variable
* @param value value of the variable
* @return the builder
*/
public K6Container withScriptVar(String key, String value) {
scriptVars.put(key, value);
return self();
}

/**
* {@inheritDoc}
*/
@Override
protected void configure() {
List<String> commandParts = new ArrayList<>();
commandParts.add("run");
commandParts.addAll(cmdOptions);
for (Map.Entry<String, String> entry : scriptVars.entrySet()) {
commandParts.add("--env");
commandParts.add(String.format("%s=%s", entry.getKey(), entry.getValue()));
}
commandParts.add(testScript);

setCommand(commandParts.toArray(new String[]{}));
}

}
@@ -0,0 +1,39 @@
package org.testcontainers.k6;

import org.junit.Test;
import org.testcontainers.containers.output.WaitingConsumer;
import org.testcontainers.utility.MountableFile;

import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;

public class K6ContainerTests {

@Test
public void k6StandardTest() throws Exception {
try (
// standard_k6 {
K6Container container =
new K6Container("grafana/k6:0.49.0")
.withTestScript(
MountableFile.forClasspathResource("scripts/test.js"))
.withScriptVar("MY_SCRIPT_VAR", "are cool!")
.withScriptVar("AN_UNUSED_VAR", "unused")
.withCmdOptions("--quiet", "--no-usage-report")
// }
) {
container.start();

WaitingConsumer consumer = new WaitingConsumer();
container.followOutput(consumer);

// Wait for test script results to be collected
consumer.waitUntil(frame ->
frame.getUtf8String().contains("iteration_duration"), 3, TimeUnit.SECONDS);
javaducky marked this conversation as resolved.
Show resolved Hide resolved

assertThat(container.getLogs()).contains("k6 tests are cool!");
}
}

}
16 changes: 16 additions & 0 deletions modules/k6/src/test/resources/logback-test.xml
@@ -0,0 +1,16 @@
<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>

<logger name="org.testcontainers" level="INFO"/>
</configuration>
6 changes: 6 additions & 0 deletions modules/k6/src/test/resources/scripts/test.js
@@ -0,0 +1,6 @@
// access_script_vars {
// The most basic of k6 scripts.
export default function(){
console.log(`k6 tests ${__ENV.MY_SCRIPT_VAR}`)
}
// }