|
|
|
@ -2,11 +2,16 @@ import http from 'k6/http';
@@ -2,11 +2,16 @@ import http from 'k6/http';
|
|
|
|
|
import ws from 'k6/ws'; |
|
|
|
|
|
|
|
|
|
import { check, sleep } from 'k6'; |
|
|
|
|
import { randomIntBetween, randomString } from "https://jslib.k6.io/k6-utils/1.0.0/index.js"; |
|
|
|
|
|
|
|
|
|
const baseUserAgent = 'Owncast LoadTest/1.0'; |
|
|
|
|
|
|
|
|
|
function randomNumber() { |
|
|
|
|
return Math.floor(Math.random() * 10000) + 1 |
|
|
|
|
return randomIntBetween(1, 10000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function randomSleep() { |
|
|
|
|
sleep(randomIntBetween(10, 60)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function pingViewerAPI() { |
|
|
|
@ -14,74 +19,95 @@ function pingViewerAPI() {
@@ -14,74 +19,95 @@ function pingViewerAPI() {
|
|
|
|
|
// sees each user as unique.
|
|
|
|
|
var params = { |
|
|
|
|
headers: { |
|
|
|
|
'User-Agent': 'test-client-' + randomNumber(), |
|
|
|
|
'User-Agent': baseUserAgent + ' ' + randomNumber(), |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
http.get('http://localhost:8080/api/ping', params); |
|
|
|
|
const response = http.get('http://localhost:8080/api/ping', params); |
|
|
|
|
check(response, { 'status was 200': (r) => r.status == 200 }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fetchHLSPlaylist() { |
|
|
|
|
http.get('http://localhost:8080/hls/stream.m3u8'); |
|
|
|
|
const response = http.get('http://localhost:8080/hls/stream.m3u8'); |
|
|
|
|
check(response, { 'status was 200': (r) => r.status == 200 }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function fetchChatHistory(accessToken) { |
|
|
|
|
const response = http.get( |
|
|
|
|
`http://localhost:8080/api/chat?accessToken=${accessToken}` |
|
|
|
|
); |
|
|
|
|
check(response, { 'status was 200': (r) => r.status == 200 }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function connectToChat() { |
|
|
|
|
const response = http.post('http://localhost:8080/api/chat/register'); |
|
|
|
|
check(response, { 'status was 200': (r) => r.status == 200 }); |
|
|
|
|
const accessToken = response.json('accessToken'); |
|
|
|
|
|
|
|
|
|
const params = { |
|
|
|
|
headers: { |
|
|
|
|
"User-Agent": `${baseUserAgent} (iteration ${__ITER}; virtual-user ${__VU})`, |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var res = ws.connect( |
|
|
|
|
function registerUser() { |
|
|
|
|
const response = http.post('http://localhost:8080/api/chat/register'); |
|
|
|
|
check(response, { 'status was 200': (r) => r.status == 200 }); |
|
|
|
|
const accessToken = response.json('accessToken'); |
|
|
|
|
|
|
|
|
|
return accessToken; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function connectToChat(accessToken) { |
|
|
|
|
// Connect to the chat server via web socket.
|
|
|
|
|
const params = { |
|
|
|
|
headers: { |
|
|
|
|
'User-Agent': `${baseUserAgent} (iteration ${__ITER}; virtual-user ${__VU})`, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var wsResponse = ws.connect( |
|
|
|
|
`ws://127.0.0.1:8080/ws?accessToken=${accessToken}`, |
|
|
|
|
params, |
|
|
|
|
function (socket) { |
|
|
|
|
socket.on('open', function (data) { |
|
|
|
|
const testMessage = { |
|
|
|
|
body: `Test message ${randomNumber()}`, |
|
|
|
|
body: `${randomString(randomIntBetween(10, 1000))} ${randomNumber()}`, |
|
|
|
|
type: 'CHAT', |
|
|
|
|
}; |
|
|
|
|
sleep(10); // After a user joins they wait 10 seconds to send a message
|
|
|
|
|
|
|
|
|
|
randomSleep(); // After a user joins they wait to send a message
|
|
|
|
|
socket.send(JSON.stringify(testMessage)); |
|
|
|
|
sleep(60); // The user waits a minute after sending a message to leave.
|
|
|
|
|
randomSleep(); // The user waits after sending a message to leave.
|
|
|
|
|
socket.close(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
check(wsResponse, { 'status was 200': (r) => r.status == 200 }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export default function () { |
|
|
|
|
const accessToken = registerUser(); |
|
|
|
|
// Fetch chat history once you have an access token.
|
|
|
|
|
fetchChatHistory(accessToken); |
|
|
|
|
|
|
|
|
|
// A client hits the ping API every once in a while to
|
|
|
|
|
// keep track of the number of viewers. So we can emulate
|
|
|
|
|
// that.
|
|
|
|
|
pingViewerAPI(); |
|
|
|
|
|
|
|
|
|
// Emulate loading the master HLS playlist
|
|
|
|
|
fetchHLSPlaylist(); |
|
|
|
|
connectToChat(); |
|
|
|
|
|
|
|
|
|
// Register as a new chat user and connect.
|
|
|
|
|
connectToChat(accessToken); |
|
|
|
|
|
|
|
|
|
sleep(8); // Emulate the ping timer on the client.
|
|
|
|
|
pingViewerAPI(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export let options = { |
|
|
|
|
userAgent: baseUserAgent, |
|
|
|
|
scenarios: { |
|
|
|
|
// starting: {
|
|
|
|
|
// executor: 'shared-iterations',
|
|
|
|
|
// gracefulStop: '5s',
|
|
|
|
|
// vus: 10,
|
|
|
|
|
// iterations: 100,
|
|
|
|
|
// env: { SEND_MESSAGES: "true" },
|
|
|
|
|
// },
|
|
|
|
|
loadstages: { |
|
|
|
|
executor: 'ramping-vus', |
|
|
|
|
startVUs: 0, |
|
|
|
|
gracefulStop: '5s', |
|
|
|
|
stages: [ |
|
|
|
|
{ duration: '10s', target: 5 }, |
|
|
|
|
{ duration: '30s', target: 100 }, |
|
|
|
|
{ duration: '120s', target: 1000 }, |
|
|
|
|
{ duration: '300s', target: 5000 }, |
|
|
|
|
], |
|
|
|
|
gracefulRampDown: '10s', |
|
|
|
|
env: { SEND_MESSAGES: "false" }, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
userAgent: baseUserAgent, |
|
|
|
|
scenarios: { |
|
|
|
|
loadstages: { |
|
|
|
|
executor: 'ramping-vus', |
|
|
|
|
startVUs: 0, |
|
|
|
|
gracefulStop: '120s', |
|
|
|
|
stages: [ |
|
|
|
|
{ duration: '10s', target: 20 }, |
|
|
|
|
{ duration: '120s', target: 1000 }, |
|
|
|
|
{ duration: '300s', target: 4000 }, |
|
|
|
|
], |
|
|
|
|
gracefulRampDown: '10s', |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|