Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into new-end-of-test-s…
Browse files Browse the repository at this point in the history
…ummary-output
  • Loading branch information
joanlopez committed Feb 7, 2025
2 parents bf19d6c + c78d99c commit 7a057b6
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 179 deletions.
1 change: 1 addition & 0 deletions .github/workflows/xk6.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defaults:
jobs:
test-xk6:
strategy:
fail-fast: false
matrix:
go: [stable, tip]
platform: [ubuntu-latest, windows-latest, macos-latest]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const options = {

// Simulated user behavior
export default function () {
let res = http.get("https://test-api.k6.io/public/crocodiles/1/");
let res = http.get("https://quickpizza.grafana.com");
// Validate response status
check(res, { "status was 200": (r) => r.status == 200 });
sleep(1);
Expand Down
112 changes: 54 additions & 58 deletions examples/experimental/redis.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,83 @@
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.1/index.js";
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",
executor: 'shared-iterations',
vus: 10,
iterations: 200,
exec: "measureRedisPerformance",
exec: 'measureRedisPerformance',
},
usingRedisData: {
executor: "shared-iterations",
executor: 'shared-iterations',
vus: 10,
iterations: 200,
exec: "measureUsingRedisData",
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
const redisClient = new redis.Client(`redis://localhost:6379`);

// Prepare an array of rating 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 function measureRedisPerformance() {
const ratingIDs = 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}`;
redisClient
.set(`foo-${exec.vu.idInTest}`, 1)
.then(() => redisClient.get(`foo-${exec.vu.idInTest}`))
.then((value) => redisClient.incrBy(`foo-${exec.vu.idInTest}`, value))
.then((_) => redisClient.del(`foo-${exec.vu.idInTest}`))
.then((_) => redisClient.exists(`foo-${exec.vu.idInTest}`))
.then((exists) => {
if (exists !== 0) {
throw new Error("foo should have been deleted");
}
});

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 function setup() {
redisClient.sadd("crocodile_ids", ...crocodileIDs);

export async function setup() {
await redisClient.sadd('rating_ids', ...ratingIDs);
}
export function measureUsingRedisData() {
// Pick a random crocodile id from the dedicated redis set,

export async function measureUsingRedisData() {
// Pick a random rating id from the dedicated redis set,
// we have filled in setup().
redisClient
.srandmember("crocodile_ids")
.then((randomID) => {
const url = `https://test-api.k6.io/public/crocodiles/${randomID}`;
const res = http.get(url);
check(res, {
"status is 200": (r) => r.status === 200,
"content-type is application/json": (r) =>
r.headers["content-type"] === "application/json",
});
return url;
})
.then((url) => redisClient.hincrby("k6_crocodile_fetched", url, 1));
const randomID = await redisClient.srandmember('rating_ids');
const url = `https://quickpizza.grafana.com/api/ratings/${randomID}`;
const res = await http.asyncRequest('GET', url, {
headers: { Authorization: 'token abcdef0123456789' },
});

check(res, { 'status is 200': (r) => r.status === 200 });

await redisClient.hincrby('k6_rating_fetched', url, 1);
}
export function teardown() {
redisClient.del("crocodile_ids");

export async function teardown() {
await redisClient.del('rating_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"));
.hgetall('k6_rating_fetched')
.then((fetched) => Object.assign(data, { k6_rating_fetched: fetched }))
.then((data) => redisClient.set(`k6_report_${Date.now()}`, JSON.stringify(data)))
.then(() => redisClient.del('k6_rating_fetched'));

return {
stdout: textSummary(data, { indent: " ", enableColors: true }),
stdout: textSummary(data, { indent: ' ', enableColors: true }),
};
}
58 changes: 0 additions & 58 deletions examples/experimental/websockets/test-api.k6.io.js

This file was deleted.

85 changes: 32 additions & 53 deletions examples/experimental/ws.js
Original file line number Diff line number Diff line change
@@ -1,76 +1,55 @@
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/timers";
import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.1.0/index.js';
import { WebSocket } from 'k6/experimental/websockets';

let chatRoomName = "publicRoom"; // choose your chat room name
let sessionDuration = randomIntBetween(5000, 60000); // user session between 5s and 1m
const sessionDuration = randomIntBetween(1000, 3000); // user session between 1s and 3s

export default function() {
export default function () {
for (let i = 0; i < 4; i++) {
startWSWorker(i);
}
}

function startWSWorker(id) {
let url = `wss://test-api.k6.io/ws/crocochat/${chatRoomName}/`;
let ws = new WebSocket(url);
ws.binaryType = "arraybuffer";
ws.addEventListener("open", () => {
ws.send(
JSON.stringify({
event: "SET_NAME",
new_name: `Croc ${__VU}:${id}`,
})
);

ws.addEventListener("message", (e) => {
let 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") {
// create a new websocket connection
const ws = new WebSocket(`wss://quickpizza.grafana.com/ws`);
ws.binaryType = 'arraybuffer';

ws.addEventListener('open', () => {
// change the user name
ws.send(JSON.stringify({ event: 'SET_NAME', new_name: `VU ${__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}`
);
console.log(`VU ${__VU}:${id} received unhandled message: ${msg.message}`);
}
});

let intervalId = setInterval(() => {
ws.send(
JSON.stringify({
event: "SAY",
message: `I'm saying ${randomString(5)}`,
})
);
}, randomIntBetween(2000, 8000)); // say something every 2-8seconds
// 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

let timeout1id = setTimeout(function() {
// 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" }));
console.log(`VU ${__VU}:${id}: ${sessionDuration}ms passed, leaving the chat`);
ws.send(JSON.stringify({ event: 'LEAVE' }));
}, sessionDuration);

let timeout2id = setTimeout(function() {
console.log(
`Closing the socket forcefully 3s after graceful LEAVE`
);
// 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);

ws.addEventListener("close", () => {
// when connection is closing, clean up the previously created timers
ws.addEventListener('close', () => {
clearTimeout(timeout1id);
clearTimeout(timeout2id);
console.log(`VU ${__VU}:${id}: disconnected`);
Expand Down
2 changes: 1 addition & 1 deletion examples/http_2.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import http from "k6/http";
import { check } from "k6";

export default function () {
check(http.get("https://test-api.k6.io/"), {
check(http.get("https://quickpizza.grafana.com"), {
"status is 200": (r) => r.status == 200,
"protocol is HTTP/2": (r) => r.proto == "HTTP/2.0",
});
Expand Down
2 changes: 1 addition & 1 deletion examples/http_get.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import http from 'k6/http';

export default function () {
http.get('https://test-api.k6.io/');
http.get('https://quickpizza.grafana.com');
};
17 changes: 12 additions & 5 deletions internal/js/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,11 @@ func TestOpen(t *testing.T) {
openPath: "/path/to/file.txt",
pwd: "/path",
},
{
name: "file scheme",
openPath: "file:///path/to/file.txt",
pwd: "/path",
},
{
name: "file is dir",
openPath: "/path/to/",
Expand Down Expand Up @@ -687,6 +692,10 @@ func TestOpen(t *testing.T) {
filePath := filepath.Join(prefix, "/path/to/file.txt")
require.NoError(t, fs.MkdirAll(filepath.Join(prefix, "/path/to"), 0o755))
require.NoError(t, fsext.WriteFile(fs, filePath, []byte(`hi`), 0o644))
fs = fsext.NewChangePathFs(fs, func(name string) (string, error) {
// Drop the prefix effectively building something like https://pkg.go.dev/os#DirFS
return filepath.Join(prefix, name), nil
})
if isWindows {
fs = fsext.NewTrimFilePathSeparatorFs(fs)
}
Expand All @@ -705,14 +714,11 @@ func TestOpen(t *testing.T) {

testFunc := func(t *testing.T) {
t.Parallel()
fs, prefix, cleanUp := fsInit()
fs, _, cleanUp := fsInit()
defer cleanUp()
fs = fsext.NewReadOnlyFs(fs)
openPath := tCase.openPath
// if fullpath prepend prefix
if openPath != "" && (openPath[0] == '/' || openPath[0] == '\\') {
openPath = filepath.Join(prefix, openPath)
}
if isWindows {
openPath = strings.ReplaceAll(openPath, `\`, `\\`)
}
Expand All @@ -724,7 +730,7 @@ func TestOpen(t *testing.T) {
export let file = open("` + openPath + `");
export default function() { return file };`

sourceBundle, err := getSimpleBundle(t, filepath.ToSlash(filepath.Join(prefix, pwd, "script.js")), data, fs)
sourceBundle, err := getSimpleBundle(t, filepath.ToSlash(filepath.Join(pwd, "script.js")), data, fs)
if tCase.isError {
require.Error(t, err)
return
Expand All @@ -749,6 +755,7 @@ func TestOpen(t *testing.T) {

t.Run(tCase.name, testFunc)
if isWindows {
tCase := tCase // copy test case before making modifications
// windowsify the testcase
tCase.openPath = strings.ReplaceAll(tCase.openPath, `/`, `\`)
tCase.pwd = strings.ReplaceAll(tCase.pwd, `/`, `\`)
Expand Down
Loading

0 comments on commit 7a057b6

Please sign in to comment.