Skip to content

k6 load testing & response times dynamic testing#83

Open
pskodr wants to merge 5 commits intomainfrom
test/k6-load-testing
Open

k6 load testing & response times dynamic testing#83
pskodr wants to merge 5 commits intomainfrom
test/k6-load-testing

Conversation

@pskodr
Copy link
Copy Markdown

@pskodr pskodr commented Mar 13, 2026

Overview

This PR integrates k6 testing into the YC 26 instance of the NodeBB repo, which is a dynamic testing tool used to test loads. k6 allows us to simulate concurrent users using the NodeBB webapp, and measures performance metrics including response times, webapp open failure rates, and throughput. The k6 test file load-test.js is written in javascript, which is a good tool and integrates well with NodeBB's node.js codebase.

Tool Name & Description

The tool used in this PR is k6. k6 is an open source dynamic analysis load testing tool which is typically used to evaluate the performance and scalability of web applications, like NodeBB, by simulating concurrent/simultaneous users and measuring how the system behaves under heavy traffic. I personally chose to test our codebase using k6, since NodeBB is a web-app that would naturally have a large concurrent user base, and the ability to concurrently run without issues is a core function of a discussion forum webapp, thus stress testing traffic management is something crucial, especially after making changes and adding features such as anonymous posting, supported by instructor, resolving posts, and a admin view of announcement viewing lists, features that rely on instantaneous change and live data syncs.

Installation Evidence:

@types/k6 was added to package.json as a dependency, k6 binary was installed locally via direct download from v.0.55.0 of k6 on github, and test scripts were created in test/k6/load-test.js

Types of Problems the Tool Catches

k6 helps us identify performance issues introduced by the new features we added into NodeBB including

  • potential increases in response time on /recent /popular /categories /api/recent end points.
  • Failures under heavy user traffic (multiple users posting anonymously at the same time, etc.)
  • Catching scalability concerns caused by our introduced features such as database querying, anonymous logic, UI rendering

What I tested specifically

  • Load test which runs against NodeBB instance, which simulates 50 concurrent virtual users over 60 seconds, targeting endpoints such as /recent, /popular, /categories, /api/recent.
  • Output artifacts from the test run can be seen in test/k6/k6-output.txt, from running command "k6 run test/k6/load-test.mjs 2>&1 | tee test/k6/k6-output.txt"

Results:

All k6 checks on the endpoints ran successfully, some failed such as homepage loading within 500ms, but 0 failed requests, successful passing runs on average response time within established thresholds, handled 50 users at once without errors, shows viability for usage for a class-setting use of NodeBB.

Customization & Configurations:

1) Priori:

  • The options block in the test script must be configured before running, which includes the number of virtual users (vus) and test duration (duration)
  • A local instance of NodeBB has to be running and accessible for k6 to execute any tests, can't test in isolation
    Routes/pages to test must be manually added to the test file, k6 can't automatically find endpoints

2) Over time:

  • As new features to NodeBB, the test script has to be updated to cover them
  • k6 can be used with CI/CD

Pros:

  • k6 requires very little setup, as all you have to do is install k6, install npm dependencies, and direct the k6 to run against a running instance of a webapp
  • k6 is javascript based, as tests are written in Javascript, which is easily integrated into a Node.js codebase
  • k6 provides quick, and extensive tests for a webapp's loading times, average response times, failure rates, which provide information about how well the webapp runs with multiple concurrent users, which is really useful for webapps involving many users like NodeBB
  • Allows for direct comparison between versions with and without features implemented (see how added features affect runtimes and response times/concurrent user response times)

Cons:

  • k6 requires a live deployment of the webapp, thus can't be run without first running an instance of the webapp
  • Limited test coverage, the tests ran using k6 only were run on unauthenticated routes, not involving logins, which requires more complex a scripting with session tokens. (Especially difficult for when testing features such as anonymous posting, and announcement viewer lists, as they require role-based login permissions, and virtual users can't simulate that unless authentication is involved, which would increase the scope of the testing significantly, and compromises the easy-testing nature of k6.
  • k6 requires manually adding scripts to cover routes every time a new feature is implemented, so it doesn't automatically cover new features/routes if you don't manually write script about it.

How can/should we integrate this into the development process?

k6 fits well into our development process as a performance validation tool for each of our added features implemented in the NodeBB codebase. Specifically, we can run local testing, by running k6 against the local NodeBB instance with our plugins and extensions to make sure our new features don't compromise traffic handling and scalability. We can also integrate k6 testing into our git workflow, by ensuring k6 tests pass and uphold stability thresholds that we want NodeBB to run at, before we commit, push or merge changes to our repository for our new features, given the features we implemented are mostly related to simultaneous use cases. Finally, we can implement k6 into CI/CD to check for performance when new features are added every time a small change or feature is pushed.

False Positives/False Negatives

Because k6 is a dynamic tool that measures real runtime behavior rather than a static analysis tool, it would generally have less false positives and false negatives. Regardless, some false positives that could occur would be incomplete endpoint coverage, meaning k6 not fully testing the runtime behavior after a certain function is triggered, but rather in its idle state, as well as lacking tests for authenticated routes that require login/role specific rendering. Some false negatives that could occur would be indication of performance problems that might be less meaningful/relevant to our webapp, such as failures from first time requests, or local runtime problems due to lack of cpu or gpu on the local device.

image

@pskodr pskodr self-assigned this Mar 13, 2026
Copilot AI review requested due to automatic review settings March 13, 2026 01:20
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Integrates a basic k6-based load test into the NodeBB repo to simulate concurrent traffic against common unauthenticated pages/API endpoints and capture performance/availability signals.

Changes:

  • Add a k6 test script that hits several NodeBB routes with simple status/latency checks.
  • Add a captured example output log from a local k6 run.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
test/k6/load-test.mjs Defines k6 scenario options and a per-iteration flow hitting multiple endpoints with check() assertions.
test/k6/k6-output.txt Adds a recorded console output artifact from a single k6 run.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread test/k6/load-test.mjs
Comment on lines +10 to +12
// Test homepage
let res = http.get('http://localhost:4567/');
check(res, {
Comment thread test/k6/load-test.mjs
Comment on lines +12 to +15
check(res, {
'homepage status is 200': (r) => r.status === 200,
'homepage loads in < 500ms': (r) => r.timings.duration < 500,
});
Comment thread test/k6/load-test.mjs
Comment on lines +11 to +38
let res = http.get('http://localhost:4567/');
check(res, {
'homepage status is 200': (r) => r.status === 200,
'homepage loads in < 500ms': (r) => r.timings.duration < 500,
});

// Test recent topics
let recent = http.get('http://localhost:4567/recent');
check(recent, {
'recent topics status is 200': (r) => r.status === 200,
'recent topics loads in < 500ms': (r) => r.timings.duration < 500,
});

// Test popular topics
let popular = http.get('http://localhost:4567/popular');
check(popular, {
'popular topics status is 200': (r) => r.status === 200,
});

// Test categories page
let categories = http.get('http://localhost:4567/categories');
check(categories, {
'categories status is 200': (r) => r.status === 200,
'categories loads in < 500ms': (r) => r.timings.duration < 500,
});

// Test API endpoint
let api = http.get('http://localhost:4567/api/recent');
Comment thread test/k6/k6-output.txt
Comment on lines +196 to +199
✓ homepage status is 200
✗ homepage loads in < 500ms
↳ 98% — ✓ 1800 / ✗ 20
✓ recent topics status is 200
Comment thread test/k6/k6-output.txt
Comment on lines +1 to +42

/\ Grafana /‾‾/
/\ / \ |\ __ / /
/ \/ \ | |/ / / ‾‾\
/ \ | ( | (‾) |
/ __________ \ |_|\_\ \_____/

execution: local
script: test/k6/load-test.mjs
output: -

scenarios: (100.00%) 1 scenario, 50 max VUs, 1m30s max duration (incl. graceful stop):
* default: 50 looping VUs for 1m0s (gracefulStop: 30s)


running (0m01.0s), 50/50 VUs, 0 complete and 0 interrupted iterations
default [ 2% ] 50 VUs 0m01.0s/1m0s

running (0m02.0s), 50/50 VUs, 0 complete and 0 interrupted iterations
default [ 3% ] 50 VUs 0m02.0s/1m0s

running (0m03.0s), 50/50 VUs, 50 complete and 0 interrupted iterations
default [ 5% ] 50 VUs 0m03.0s/1m0s

running (0m04.0s), 50/50 VUs, 50 complete and 0 interrupted iterations
default [ 7% ] 50 VUs 0m04.0s/1m0s

running (0m05.0s), 50/50 VUs, 100 complete and 0 interrupted iterations
default [ 8% ] 50 VUs 0m05.0s/1m0s

running (0m06.0s), 50/50 VUs, 100 complete and 0 interrupted iterations
default [ 10% ] 50 VUs 0m06.0s/1m0s

running (0m07.0s), 50/50 VUs, 150 complete and 0 interrupted iterations
default [ 12% ] 50 VUs 0m07.0s/1m0s

running (0m08.0s), 50/50 VUs, 150 complete and 0 interrupted iterations
default [ 13% ] 50 VUs 0m08.0s/1m0s

running (0m09.0s), 50/50 VUs, 200 complete and 0 interrupted iterations
default [ 15% ] 50 VUs 0m09.0s/1m0s

Comment thread test/k6/load-test.mjs
Comment on lines +4 to +6
export const options = {
vus: 50, // 50 virtual users
duration: '60s', // run for 60 seconds
@pskodr pskodr changed the title Test/k6 load testing k6 load testing & response times dynamic testing Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants