Skip to content
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

Test: added performance test script for irma server #294

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,21 @@ irma server -vv --store-type redis --redis-addr "localhost:6379" --redis-allow-e
```

## Performance tests
This project only includes performance tests for the `irma keyshare server`. These tests can be run using the [k6 load testing tool](https://k6.io/docs/) and need a running keyshare server instance to test against. Instructions on how to run a keyshare server locally can be found [above](#running).
This project only includes performance tests for the `irma server` and the `irma keyshare server`. These tests can be run using the [k6 load testing tool](https://k6.io/docs/) and need a running server instance to test against.

The performance tests can be started in the following way:
Instructions on how to run `irma server` locally with a Redis datastore can be found [here](#using-a-local-redis-datastore). Instructions on how to run a keyshare server locally can be found [here](#running).

```
go install go.k6.io/k6@latest
k6 run ./testdata/performance/keyshare-server.js --env URL=http://localhost:8080 --env ISSUER_ID=test.test
```
First, you need to install `k6`:

go install go.k6.io/k6@latest

The performance tests of the `irma server` can be started in the following way:

k6 run ./testdata/performance/irma-server.js --env URL=http://localhost:8088

The performance tests of the keyshare server can be started in the following way:

k6 run ./testdata/performance/keyshare-server.js --env URL=http://localhost:8080 --env ISSUER_ID=test.test

By default, k6 runs a single test iteration using 1 virtual user. These defaults can be adjusted by specifying test stages using the [`-s` CLI parameter](https://k6.io/docs/using-k6/options/#stages).

Expand Down
1 change: 1 addition & 0 deletions testdata/configurations/keyshareserver.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
verbose: 2

schemes_path: testdata/irma_configuration
schemes_assets_path: testdata/irma_configuration # To prevent assets from Docker image to be used
schemes_update: 0
privkeys: testdata/privatekeys
url: http://localhost:8080/
Expand Down
1 change: 1 addition & 0 deletions testdata/configurations/myirmaserver.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
verbose: 2

schemes_path: testdata/irma_configuration
schemes_assets_path: testdata/irma_configuration # To prevent assets from Docker image to be used
schemes_update: 0
url: http://localhost:port/
port: 8081
Expand Down
70 changes: 70 additions & 0 deletions testdata/performance/irma-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { check, fail, sleep } from 'k6';
import http from 'k6/http';

const url = __ENV.URL;

export const options = {
minIterationDuration: '30s',
thresholds: {
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
},
};

function checkResponse(response, expectedOutput = '') {
const checkOutput = check(response, {
'verify response': (r) => r.error === '',
'verify status code': (r) => r.status === 200,
'verify body': (r) => r.body != null && r.body.includes(expectedOutput),
});
if (!checkOutput) fail(`unexpected response: url ${response.request.url}, status ${response.status}, error "${response.error}", body "${response.body}"`);
}

export default function () {
const newSessionResp = http.post(`${url}/session`, JSON.stringify({
"@context": "https://irma.app/ld/request/disclosure/v2",
"disclose": [
[
["irma-demo.sidn-pbdf.email.email"]
]
]
}), {
headers: {
'Content-Type': 'application/json',
},
});
checkResponse(newSessionResp);

const sessionPackage = newSessionResp.json();
const sessionPtrUrl = sessionPackage.sessionPtr.u;

for (let i = 0; i < 10; i++) {
let statusResp = http.get(`${sessionPtrUrl}/status`);
checkResponse(statusResp, 'INITIALIZED');
sleep(1);
}

const sessionResp = http.get(sessionPtrUrl, {
headers: {
'Authorization': '12345',
'X-IRMA-MinProtocolVersion': '2.8',
'X-IRMA-MaxProtocolVersion': '2.8',
},
});
checkResponse(sessionResp, '"protocolVersion":"2.8"');

for (let i = 0; i < 20; i++) {
let statusResp = http.get(`${sessionPtrUrl}/status`);
checkResponse(statusResp, 'CONNECTED');
sleep(1);
}

const sessionDeletedResp = http.del(sessionPtrUrl);
checkResponse(sessionDeletedResp);

let statusResp = http.get(`${sessionPtrUrl}/status`);
checkResponse(statusResp, 'CANCELLED');

let sessionResultResp = http.get(`${url}/session/${sessionPackage.token}/result`);
checkResponse(sessionResultResp, 'CANCELLED');
}
22 changes: 17 additions & 5 deletions testdata/performance/keyshare-server.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fail } from 'k6';
import { check, fail } from 'k6';
import { instance, vu } from 'k6/execution';
import http from 'k6/http';

Expand All @@ -14,6 +14,15 @@ export const options = {
},
};

function checkResponse(response, expectedOutput = '') {
const checkOutput = check(response, {
'verify response': (r) => r.error === '',
'verify status code': (r) => r.status === 200,
'verify body': (r) => r.body != null && r.body.includes(expectedOutput),
});
if (!checkOutput) fail(`unexpected response: url ${response.request.url}, status ${response.status}, error "${response.error}", body "${response.body}"`);
}

export function setup() {
if (!url || !issuerID) {
fail('Must specify URL and ISSUER_ID options via environment variables');
Expand All @@ -27,12 +36,13 @@ export function setup() {
const registerPayloadStr = JSON.stringify(registerPayload);

// An IRMA account cannot be used in parallel, so every VU needs its own account.
const testAccounts = Array.from({length: instance.vusInitialized}, () => {
const testAccounts = Array.from({ length: instance.vusInitialized }, () => {
const registerResp = http.post(`${url}/client/register`, registerPayloadStr, {
headers: {
'Content-Type': 'application/json',
},
});
checkResponse(registerResp);

const sessionResp = http.get(registerResp.json().u, {
headers: {
Expand All @@ -41,8 +51,9 @@ export function setup() {
'X-IRMA-MaxProtocolVersion': '2.8',
},
});
checkResponse(sessionResp);
ivard marked this conversation as resolved.
Show resolved Hide resolved

http.del(registerResp.json().u);
checkResponse(http.del(registerResp.json().u));

return {
id: Object.values(sessionResp.json().request.credentials[0].attributes)[0],
Expand All @@ -59,6 +70,7 @@ export default function ({ testAccounts }) {
const testAccount = testAccounts[vu.idInTest - 1];

const pinResp = http.post(`${url}/users/verify/pin`, JSON.stringify(testAccount));
checkResponse(pinResp);

const proveParams = {
headers: {
Expand All @@ -67,7 +79,7 @@ export default function ({ testAccounts }) {
},
};

http.post(`${url}/prove/getCommitments`, `["${issuerID}-0"]`, proveParams);
checkResponse(http.post(`${url}/prove/getCommitments`, `["${issuerID}-0"]`, proveParams));

http.post(`${url}/prove/getResponse`, '"5adEmlEg9U2zjNlPxyPvRym2AzWkBo4kIZJ7ytNg0q0="', proveParams);
checkResponse(http.post(`${url}/prove/getResponse`, '"5adEmlEg9U2zjNlPxyPvRym2AzWkBo4kIZJ7ytNg0q0="', proveParams));
}