8000 Add a simple k6 stresstest script by elisescu · Pull Request #417 · Metaculus/metaculus · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add a simple k6 stresstest script #417

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

Merged
merged 1 commit into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions scripts/k6-stress/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Stress testing simple scripts

These require [k6](https://grafana.com/docs/k6/latest/), so make sure to install that as explained in their documentation.

Please don't run them against the production environment.

### How to run:

```bash
MAX_DURATION=500s BASE_URL=https://dev.metaculus.com METACULUS_API_TOKEN=<token_for_user_predicting> API_VUS=200 UI_VUS=5 ITERATIONS_PER_VU=10 K6_BROWSER_HEADLESS=true k6 run scripts/k6-stress/simple-stress.js
```
153 changes: 153 additions & 0 deletions scripts/k6-stress/simple-stress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { browser } from "k6/browser";
import { check, sleep } from "k6";
import { parseHTML } from "k6/html";
import http from "k6/http";

// URL of the site to run stress tests against
const BASE_URL = __ENV.BASE_URL ?? "http://localhost:3000";

// Number of virtual users that will make requests with the browser (i.e. request all the other resources needed to render the main html: css, js, etc)
const UI_VUS = __ENV.UI_VUS ?? 5;
// Number of virtual users that will make a simple http request (REST API)
const API_VUS = __ENV.API_VUS ?? 50;
// NUmber of iterations roughly each user to do. This is multiplied with the number of users, as they are shared by the shared-iterations executor
// (see more: https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/shared-iterations/)
const ITERATIONS_PER_VU = __ENV.ITERATIONS_PER_VU ?? 5;
// Maximum duration for the stress test to run
const MAX_DURATION = __ENV.MAX_DURATION ?? "60s";

// Token used to authenticate the Metaculus user used to post predictions on a question
const METACULUS_API_TOKEN = __ENV.METACULUS_API_TOKEN ?? "not-set";

export const options = {
scenarios: {
questionDetailsPage: {
executor: "shared-iterations",
vus: UI_VUS,
iterations: ITERATIONS_PER_VU * UI_VUS,
maxDuration: MAX_DURATION,
exec: "questionDetailsPage",
startTime: "0s",
options: {
browser: {
type: "chromium",
},
},
},
questionsListFeedPage: {
executor: "shared-iterations",
vus: UI_VUS,
iterations: ITERATIONS_PER_VU * UI_VUS,
maxDuration: MAX_DURATION,
exec: "questionsListFeedPage",
startTime: "0s",
options: {
browser: {
type: "chromium",
},
},
},
questionsListAPI: {
executor: "shared-iterations",
vus: API_VUS,
iterations: ITERATIONS_PER_VU * API_VUS,
maxDuration: MAX_DURATION,
exec: "questionsListAPI",
startTime: "0s",
},
predictOnQuestionAPI: {
executor: "shared-iterations",
vus: API_VUS,
iterations: ITERATIONS_PER_VU * API_VUS,
maxDuration: MAX_DURATION,
exec: "predictOnQuestionAPI",
startTime: "0s",
},
},
};

export async function predictOnQuestionAPI() {
const url = BASE_URL + "/api2/questions/349/predict/";
const res = http.post(url, JSON.stringify({ prediction: 0.8 }), {
headers: {
"Content-Type": "application/json",
Authorization: `Token ${METACULUS_API_TOKEN}`,
},
});

check(res, {
"API /predict/ returned 201": (r) => r.status === 201,
});
sleep(0.5);
}

export async function questionsListAPI() {
const url = BASE_URL + "/api2/questions/?offset=0&limit=20";
const res = http.get(url);

check(res, {
"API questions list returned 200": (r) => r.status === 200,
"API questions returned all requests questions": (r) =>
r.json().results?.length === 20,
});
sleep(0.5);
}

export async function questionsListFeedPage() {
const context = await browser.newContext();
const page = await context.newPage();

try {
await page.goto(BASE_URL + "/questions/"); // Will SpaceX land people on Mars before 2030?

const sideBar = await page
.locator("main > div > div.sticky.top-12")
.textContent();

const listOfQuestionsHTML = await page
.locator("main > div > div.grow.overflow-x-hidden > div.flex.flex-col")
.innerHTML();

const listOfQuestoinsTitles = parseHTML(listOfQuestionsHTML).find("a>h4");

check(sideBar, {
"Sidebar includes 'Feed Home'": (sideBar) =>
sideBar.includes("Feed Home"),
"Sidebar includes 'TOPICS' section": (sideBar) =>
sideBar.includes("Topics"),
"Sidebar includes 'CATEGORIES' section": (sideBar) =>
sideBar.includes("categories"),
});

check(listOfQuestoinsTitles, {
"Rendered 10 questions": (listOfQuestoinsTitles) =>
listOfQuestoinsTitles.size() >= 10,
});
} finally {
await page.close();
}
}

export async function questionDetailsPage() {
const context = await browser.newContext();
const page = await context.newPage();

try {
await page.goto(BASE_URL + "/questions/349/"); // Will SpaceX land people on Mars before 2030?

const titleH1 = await page.locator("main h1").textContent();
check(titleH1, {
"Question title renders": (h1) => h1.includes("Will SpaceX"),
});

const predictButton = await page.locator(
"#prediction-section > div.mt-3 > div.flex.flex-col.items-center.justify-center > button"
);

check(predictButton, {
"Predict Button renders": (button) => button.isVisible(),
});
} finally {
await page.close();
}
}
0