Skip to content

6234 - Stress test - Data entry: Tables & NDP - #6254

Open
yaguzmang wants to merge 8 commits into
6234-stress-testfrom
6234-stress-test-2
Open

6234 - Stress test - Data entry: Tables & NDP#6254
yaguzmang wants to merge 8 commits into
6234-stress-testfrom
6234-stress-test-2

Conversation

@yaguzmang

Copy link
Copy Markdown
Contributor

No description provided.

Comment thread src/tools/stressTest/config.ts
@yaguzmang
yaguzmang marked this pull request as ready for review August 24, 2026 23:19
editNdp(headers, countryIso, ndps)
}

sleep(randomInt(pauseMinSeconds, pauseMaxSeconds))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The if else logic is a bit difficult to understand.
Maybe it's better if we have one stress test per case ?
Data entry
Edit NDP
Edit descriptions

@sorja what do you think ?

@sorja sorja Aug 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sounds good

I would do something similar to:

src/tools/stressTest/tableData.ts
src/tools/stressTest/ndpData.ts
src/tools/stressTest/descriptions.ts

--

Something else:

Not sure where we should fetch validations (GET request), for me it would make more sense to:

in case of {table data / ndp / description}:
write: {}
read: {}

Means:
when stress testing table data, I would also try to fetch the same data
when stress testing ndp (e.g. year 2020), i would try to fetch the same ndp to see that it responds
etc

Does this make sense?

-- After thought --
Maybe we can fetch both validations AND table data in the canary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. I split it into one test per case: tableData/ and ndp/
run.sh now takes the test as an argument:

./src/tools/stressTest/run.sh <host> <email> <password>        # tableData (default)
./src/tools/stressTest/run.sh <host> <email> <password> ndp

@sorja I added a canary at a fixed rate (2/s) that fetches the data being written and its validations 👍

Comment thread src/tools/stressTest/tableData/index.ts Outdated
export const read = (data: { token: string }): void => {
const headers = { Cookie: `fra-auth-token=${data.token}` }
const countryIso = countries[randomInt(0, countries.length - 1)]
getTableData(headers, countryIso)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we also get validations here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i see now that they are fetched with getTableData
should we use getValidations?

const headers = { 'Content-Type': 'application/json', Cookie: `fra-auth-token=${data.token}` }
const countryIso = countries[__VU % countries.length] // spreads simulated users across countries
editTableCells(headers, countryIso)
sleep(randomInt(pauseMinSeconds, pauseMaxSeconds))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not sure if this is needed, i think constant pause or no pause is enough

for stress test, does it add value to have a random interval pause?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, the initial idea was to simulate 100 users, so a pause like this helps mimic user behaviour better.

headers,
tags: { name: 'validations/table-data GET' },
})
check(validations, { 'table validations ok': (res) => res.status === 200 })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what do you think?

Suggested change
check(validations, { 'table validations ok': (res) => res.status === 200 })
// import { RequestUtils } ...
check(validations, { 'table validations ok': RequestUtils.isOk)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we have Requests.sendOk

const params = `${cycleParams(countryIso)}&sectionName=extentOfForest`

const one = http.get(
`${baseUrl}/api/cycle-data/national-data-points/national-data-point?${params}&year=${ndp.year}`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can't use ApiEndPoint here (mentioned in readme) these files run inside k6, not Node. k6 bundles the scripts with its own loader, which doesn't understand our tsconfig path aliases, and ApiEndPoint imports its own modules through those aliases (meta/api/endpoint/...), so the import fails. Only type imports work, because they are erased at build time.

I can check if I can add a pre-bundle step in the sh script and maybe then we can import normal platform code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I checked the docs and we can do something like this in run.sh to bundle before running the tests using rolldown (a vite dependency):

#!/bin/sh
# Runs a stress test against the given environment. See README.md.

<...usage...>

# Paths are resolved relative to this file, so run.sh works from any directory
dir="$(dirname "$0")"
root="$dir/../../.."
test="${4:-tableData}"
bundle="$root/.tmp/stressTest-$test.js" # a file per test so concurrent runs of different tests don't collide

# Bundle the test first so it is possible resolve import aliases
mkdir -p "$root/.tmp"
"$root/node_modules/.bin/rolldown" "$dir/$test/index.ts" --external k6 --external k6/http \
  --format esm --platform neutral --tsconfig "$root/tsconfig.json" --file "$bundle" >/dev/null

exec k6 run -e HOST="$1" -e STRESS_TEST_EMAIL="$2" -e STRESS_TEST_PASSWORD="$3" "$bundle"

@sorja @minotogna what do you think? this way we can import ApiEndPoint, Numbers.randomInt, RequestUtils.isOk etc...

const originalDataPoint = { ...ndp, values: { ...ndp.values, forestArea: String(randomInt(0, 1000)) } }
const params = `${cycleParams(countryIso)}&sectionName=extentOfForest`
const response = http.put(
`${baseUrl}/api/cycle-data/national-data-points/national-data-point/original-data?${params}`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints

Comment thread src/tools/stressTest/ndp/getNdp.ts Outdated
)
check(one, { 'ndp read ok': (res) => res.status === 200 })

const validations = http.get(`${baseUrl}/api/cycle-data/validations/national-data-points?${params}`, {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints


const ndpsByCountry: Record<string, Array<OriginalDataPoint>> = {}
countries.forEach((countryIso) => {
const response = http.get(`${baseUrl}/api/cycle-data/national-data-points?${cycleParams(countryIso)}`, { headers })

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints

tableName: cell.tableName,
values: [{ colName: cell.colName, value: { raw: String(randomInt(0, 1000)) }, variableName: cell.variableName }],
}
const response = http.patch(`${baseUrl}/api/cycle-data/table/nodes?${params}`, JSON.stringify(body), {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints


// mergeOdp=false like UI requests
const tableData = http.get(
`${baseUrl}/api/cycle-data/table/table-data?${params}&countryISOs[]=${countryIso}&mergeOdp=false`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints

)
check(tableData, { 'table data ok': (res) => res.status === 200 })

const validations = http.get(`${baseUrl}/api/cycle-data/validations/table-data?${params}`, {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should use ApiEndpoints . please, let's not hardcode api endpoints

@@ -0,0 +1 @@
export const randomInt = (min: number, max: number): number => min + Math.floor(Math.random() * (max - min + 1))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe better our utils Numbers.randomInt ?

@sorja

sorja commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Should we have util for urls?

Something like

Urls.getTableRead({ params })

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.

3 participants