Skip to content

Commit

Permalink
Merge pull request #4131 from grafana/websocketsMerge
Browse files Browse the repository at this point in the history
Experimental Websockets merge
  • Loading branch information
mstoykov authored Jan 15, 2025
2 parents f2d1ad8 + 4cf561d commit 613b0ad
Show file tree
Hide file tree
Showing 21 changed files with 2,679 additions and 671 deletions.
58 changes: 58 additions & 0 deletions examples/experimental/websockets/test-api.k6.io.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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


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') {
console.error(`VU ${__VU}:${id} received:: ${msg.message}`)
}
else {
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


let timeout1id = setTimeout(function() {
clearInterval(intervalId)
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`);
ws.close();
}, sessionDuration + 3000);

ws.addEventListener("close", () => {
clearTimeout(timeout1id);
clearTimeout(timeout2id);
console.log(`VU ${__VU}:${id}: disconnected`);
})
});
}

76 changes: 76 additions & 0 deletions examples/experimental/websockets/test-echo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { WebSocket } from "k6/experimental/websockets"

const CLOSED_STATE = 3

export default function() {
// local echo server should be launched with `make ws-echo-server-run`
var url = "wss://echo.websocket.org/"
var params = { "tags": { "my_tag": "hello" } };

let ws = new WebSocket(url, null, params)
ws.binaryType = "arraybuffer";
ws.onopen = () => {
console.log('connected')
ws.send(Date.now().toString())
}

let intervalId = setInterval(() => {
ws.ping();
console.log("Pinging every 1 sec (setInterval test)")
}, 1000);

let timeout1id = setTimeout(function() {
console.log('2 seconds passed, closing the socket')
clearInterval(intervalId)
ws.close()

}, 2000);

ws.onclose = () => {
clearTimeout(timeout1id);

console.log('disconnected')
}


ws.onping = () => {
console.log("PING!")
}

ws.onpong = () => {
console.log("PONG!")
}

// Multiple event handlers on the same event
ws.addEventListener("pong", () => {
console.log("OTHER PONG!")
})

ws.onmessage = (m) => {
let parsed = parseInt(m.data, 10)
if (Number.isNaN(parsed)) {
console.log('Not a number received: ', m.data)

return
}

console.log(`Roundtrip time: ${Date.now() - parsed} ms`);

let timeoutId = setTimeout(function() {
if (ws.readyState == CLOSED_STATE) {
console.log("Socket closed, not sending anything");

clearTimeout(timeoutId);
return;
}

ws.send(Date.now().toString())
}, 500);
}

ws.onerror = (e) => {
if (e.error != "websocket: close sent") {
console.log('An unexpected error occurred: ', e.error);
}
};
};
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ require (
github.com/grafana/xk6-output-prometheus-remote v0.5.0
github.com/grafana/xk6-redis v0.3.1
github.com/grafana/xk6-webcrypto v0.5.0
github.com/grafana/xk6-websockets v0.7.2
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
github.com/jhump/protoreflect v1.17.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ github.com/grafana/xk6-redis v0.3.1 h1:RqfmMLNx7vekBxwuTrFP9ErxeY/0H07a3HpQJYXYD
github.com/grafana/xk6-redis v0.3.1/go.mod h1:3e/U9i1Nm3WEaMy4nZSGMjVf8ZsFau+aXurYJhJ7MfQ=
github.com/grafana/xk6-webcrypto v0.5.0 h1:a5NMG/4itLDWprn5XbGaARwUdGPy9wO9z35Z7bDjG1k=
github.com/grafana/xk6-webcrypto v0.5.0/go.mod h1:yZMp9ZjcxLZML2ljcK6CxTI+XTP59vivtKszaH5xIE4=
github.com/grafana/xk6-websockets v0.7.2 h1:hwZfk+1zMLJZ2vXqy8WqShG4toHgY6Gw7EdFU37dSXg=
github.com/grafana/xk6-websockets v0.7.2/go.mod h1:91oE+otLmjYsPwBvxfv1+6tmoXKPZRPOXTnJveAs5Nk=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
Expand Down
4 changes: 2 additions & 2 deletions js/jsmodules.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"go.k6.io/k6/js/modules/k6/experimental/csv"
"go.k6.io/k6/js/modules/k6/experimental/fs"
"go.k6.io/k6/js/modules/k6/experimental/streams"
expws "go.k6.io/k6/js/modules/k6/experimental/websockets"
"go.k6.io/k6/js/modules/k6/grpc"
"go.k6.io/k6/js/modules/k6/html"
"go.k6.io/k6/js/modules/k6/http"
Expand All @@ -26,7 +27,6 @@ import (

"github.com/grafana/xk6-redis/redis"
"github.com/grafana/xk6-webcrypto/webcrypto"
expws "github.com/grafana/xk6-websockets/websockets"
)

func getInternalJSModules() map[string]interface{} {
Expand All @@ -42,7 +42,7 @@ func getInternalJSModules() map[string]interface{} {
"k6/experimental/redis": redis.New(),
"k6/experimental/streams": streams.New(),
"k6/experimental/webcrypto": webcrypto.New(),
"k6/experimental/websockets": &expws.RootModule{},
"k6/experimental/websockets": expws.New(),
"k6/experimental/timers": newRemovedModule(
"k6/experimental/timers has been graduated, please use k6/timers instead."),
"k6/experimental/tracing": newRemovedModule(
Expand Down
25 changes: 25 additions & 0 deletions js/modules/k6/experimental/websockets/autobahn_tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Autobahn test suite

Docs: https://github.com/crossbario/autobahn-testsuite

## Usage

Run the WebSocket server.

```sh
$ docker run -it --rm \
-v ${PWD}/config:/config \
-v ${PWD}/reports:/reports \
-p 9001:9001 \
-p 8080:8080 \
--name fuzzingserver \
crossbario/autobahn-testsuite
```

Run the autobahn client test with k6.

```sh
./k6 run ./script.js
```

Open the browser to `http://localhost:8080` for checking the report.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"url": "ws://127.0.0.1:9001",
"outdir": "./reports/clients",
"cases": ["*"],
"exclude-cases": [
"9.*",
"12.*",
"13.*"
],
"exclude-agent-cases": {}
}
Empty file.
46 changes: 46 additions & 0 deletions js/modules/k6/experimental/websockets/autobahn_tests/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { WebSocket } from "k6/x/websockets"
import { sleep, check } from "k6"
import exec from 'k6/execution'

export let options = {
iterations: 247, // get this value from the Autobahn server
vus: 3,
}

const base = `ws://127.0.0.1:9001`
const agent = "k6v383"

export default function() {
let testCase = exec.scenario.iterationInTest+1
let url = `${base}/runCase?case=${testCase}&agent=${agent}`;
let ws = new WebSocket(url);

ws.addEventListener("open", () => {
console.log(`Testing case #${testCase}`)
});

ws.addEventListener("message", (e) => {
if (e.event === 'ERROR') {
console.log(`VU ${__VU}: test: #${testCase} error:`, e.data, `and message:`, e.message)
return
}
ws.send(e.data)
})

ws.addEventListener("error", (e) => {
console.error(`test: #${testCase} error:`, e)
ws.close()
})
}

export function teardown() {
let ws = new WebSocket(`${base}/updateReports?agent=${agent}`)
ws.addEventListener("open", (e) => {
console.log("Updating the report")
});

ws.addEventListener("error", (e) => {
console.error("Updating the report failed:", e)
ws.close()
});
}
Loading

0 comments on commit 613b0ad

Please sign in to comment.