diff --git a/scripts/k6/.mise.toml b/scripts/k6/.mise.toml new file mode 100644 index 000000000..126f68073 --- /dev/null +++ b/scripts/k6/.mise.toml @@ -0,0 +1,2 @@ +[tools] +node = "20" diff --git a/scripts/k6/README.md b/scripts/k6/README.md index bbd4be105..d2061eac3 100644 --- a/scripts/k6/README.md +++ b/scripts/k6/README.md @@ -16,3 +16,24 @@ Configure local environment variables: ``` cp env.local .env.local ``` + +### Running Biome to lint/format code: +``` +# Use mise to install Node +mise install + +# Use npm to install Biome - `ci` for frozen lockfile +npm ci + +# check formatting but don't actually write anything +npm run format:check + +# format code +npm run format + +# check linting but don't try to auto-fix +npm run lint + +# lint and auto-fix if possible +npm run lint:fix +``` diff --git a/scripts/k6/biome.json b/scripts/k6/biome.json new file mode 100644 index 000000000..635034232 --- /dev/null +++ b/scripts/k6/biome.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", + "organizeImports": { + "enabled": true + }, + "files": { + "ignore": ["node_modules", "output"] + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + }, + "ignore": ["node_modules", "output"] + } +} diff --git a/scripts/k6/env.sh b/scripts/k6/env.sh index 0b79c07fd..1a1115be8 100644 --- a/scripts/k6/env.sh +++ b/scripts/k6/env.sh @@ -6,9 +6,9 @@ fi export K6_STATSD_ENABLE_TAGS=true export SKIP_DELETE_ISSUERS=true -export VUS=1 -export ITERATIONS=5 -export ISSUER_PREFIX=k6_issuer_dev2 -export HOLDER_PREFIX=k6_holder_dev_a +export VUS=5 +export ITERATIONS=2 +export ISSUER_PREFIX=k6_issuer +export HOLDER_PREFIX=k6_holder export SCHEMA_NAME="proof_of_person" export SCHEMA_VERSION="0.1.0" diff --git a/scripts/k6/package-lock.json b/scripts/k6/package-lock.json new file mode 100644 index 000000000..058683629 --- /dev/null +++ b/scripts/k6/package-lock.json @@ -0,0 +1,167 @@ +{ + "name": "k6", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@biomejs/biome": "^1.8.3" + } + }, + "node_modules/@biomejs/biome": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.3.tgz", + "integrity": "sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.8.3", + "@biomejs/cli-darwin-x64": "1.8.3", + "@biomejs/cli-linux-arm64": "1.8.3", + "@biomejs/cli-linux-arm64-musl": "1.8.3", + "@biomejs/cli-linux-x64": "1.8.3", + "@biomejs/cli-linux-x64-musl": "1.8.3", + "@biomejs/cli-win32-arm64": "1.8.3", + "@biomejs/cli-win32-x64": "1.8.3" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.3.tgz", + "integrity": "sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.3.tgz", + "integrity": "sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.3.tgz", + "integrity": "sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.3.tgz", + "integrity": "sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.3.tgz", + "integrity": "sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.3.tgz", + "integrity": "sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.3.tgz", + "integrity": "sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.3.tgz", + "integrity": "sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + } + } +} diff --git a/scripts/k6/package.json b/scripts/k6/package.json new file mode 100644 index 000000000..f74d932ef --- /dev/null +++ b/scripts/k6/package.json @@ -0,0 +1,11 @@ +{ + "scripts": { + "format:check": "biome format .", + "format": "biome format --write .", + "lint:fix": "biome lint --write --unsafe .", + "lint": "biome lint ." + }, + "devDependencies": { + "@biomejs/biome": "^1.8.3" + } +} diff --git a/scripts/k6/run_tests.sh b/scripts/k6/run_tests.sh index 5760ba8d0..68b18f91d 100755 --- a/scripts/k6/run_tests.sh +++ b/scripts/k6/run_tests.sh @@ -17,7 +17,11 @@ run_test() { run_test true true ./scenarios/create-holders.js run_test true true ./scenarios/create-invitation.js run_test true true ./scenarios/create-credentials.js -run_test true true ./scenarios/create-proof.js -run_test false false ./scenarios/delete-holders.js +run_test false true ./scenarios/create-proof.js +run_test true false ./scenarios/delete-holders.js + +run_test false true ./scenarios/create-issuers.js echo "All tests completed successfully" + +# TODO: Better logic to handle deleting issuers and holders diff --git a/scripts/k6/scenarios/create-issuers.js b/scripts/k6/scenarios/create-issuers.js new file mode 100644 index 000000000..a937af42e --- /dev/null +++ b/scripts/k6/scenarios/create-issuers.js @@ -0,0 +1,130 @@ +/* global __ENV, __ITER, __VU */ +// Solve Codacy '__ENV' is not defined. error + +import { check } from 'k6'; +import { SharedArray } from 'k6/data'; +import { getBearerToken } from '../libs/auth.js'; +import { Trend, Counter } from 'k6/metrics'; +import { + getWalletIdByWalletName, + deleteTenant, + createIssuerTenant, + getTrustRegistryActor, + createCredentialDefinition, +} from '../libs/functions.js'; + +const vus = parseInt(__ENV.VUS, 10); +const iterations = parseInt(__ENV.ITERATIONS, 10); +const issuerPrefix = __ENV.ISSUER_PREFIX; +// const holderPrefix = __ENV.HOLDER_PREFIX; + +export let options = { + scenarios: { + default: { + executor: 'per-vu-iterations', + vus: vus, + iterations: iterations, + maxDuration: '24h', + }, + }, + setupTimeout: '300s', // Increase the setup timeout to 120 seconds + teardownTimeout: '120s', // Increase the teardown timeout to 120 seconds + maxRedirects: 4, + thresholds: { //https://community.grafana.com/t/ignore-http-calls-made-in-setup-or-teardown-in-results/97260/2 + 'http_req_duration{scenario:default}': [`max>=0`], + 'http_reqs{scenario:default}': ['count >= 0'], + 'iteration_duration{scenario:default}': ['max>=0'], + }, + tags: { + test_run_id: 'phased-issuance', + test_phase: 'create-issuers', + }, +}; + +const testFunctionReqs = new Counter('test_function_reqs'); +const mainIterationDuration = new Trend('main_iteration_duration'); + +// Seed data: Generating a list of options.iterations unique wallet names +const wallets = new SharedArray('wallets', function() { + const walletsArray = []; + for (let i = 0; i < options.scenarios.default.iterations * options.scenarios.default.vus; i++) { + walletsArray.push({ + walletLabel: `${issuerPrefix} ${i}`, + walletName: `${issuerPrefix}_${i}` + }); + } + return walletsArray; +}); + +export function setup() { + const bearerToken = getBearerToken(); + return { bearerToken }; +} + +const iterationsPerVU = options.scenarios.default.iterations; +// Helper function to calculate the wallet index based on VU and iteration +function getWalletIndex(vu, iter) { + const walletIndex = (vu - 1) * iterationsPerVU + (iter - 1); + return walletIndex; +} + +export default function(data) { + const start = Date.now(); + const bearerToken = data.bearerToken; + const walletIndex = getWalletIndex(__VU, __ITER + 1); // __ITER starts from 0, adding 1 to align with the logic + const wallet = wallets[walletIndex]; + const credDefTag = wallet.walletName; + + const createIssuerTenantResponse = createIssuerTenant(bearerToken, wallet.walletName); + check(createIssuerTenantResponse, { + "Issuer tenant created successfully": (r) => r.status === 200 + }); + const issuerAccessToken = createIssuerTenantResponse.json().access_token; + + const getTrustRegistryActorResponse = getTrustRegistryActor(wallet.walletName); + check(getTrustRegistryActorResponse, { + "Trust Registry Actor Response status code is 200": (r) => { + if (r.status !== 200) { + console.error(`Unexpected response status while getting trust registry actor for issuer tenant ${wallet.walletName}: ${r.status}`); + return false; + } else { + console.log(`Got trust registry actor for issuer tenant ${wallet.walletName} successfully.`); + return true; + } + } + }); + + // const createCredentialDefinitionResponse = createCredentialDefinition(bearerToken, issuerAccessToken, credDefTag); + // check(createCredentialDefinitionResponse, { + // "Credential definition created successfully": (r) => r.status === 200 + // }); + + const end = Date.now(); + const duration = end - start; + // console.log(`Duration for iteration ${__ITER}: ${duration} ms`); + mainIterationDuration.add(duration); + testFunctionReqs.add(1); +} + +export function teardown(data) { + const bearerToken = data.bearerToken; + + // // Delete issuer tenants + if (__ENV.SKIP_DELETE_ISSUERS !== 'true') { + for (const wallet of wallets) { + const walletId = getWalletIdByWalletName(bearerToken, wallet.walletName); + const deleteIssuerResponse = deleteTenant(bearerToken, walletId); + check (deleteIssuerResponse, { + "Delete Issuer Tenant Response status code is 200": (r) => { + if (r.status !== 200) { + console.error(`Unexpected response status while deleting issuer tenant ${walletId}: ${r.status}`); + return false; + } else { + console.log(`Deleted issuer tenant ${walletId} successfully.`); + return true; + } + } + }); + } + } +}