Skip to content

Commit 9412a85

Browse files
authored
chore(performance): Make improved tests for search (#1983)
Improved test for serviceowner search, uses combinations of query-options ## Description ## Related Issue(s) - #1982 ## Verification - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) ## Documentation - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable)
1 parent 224e837 commit 9412a85

File tree

6 files changed

+244
-26
lines changed

6 files changed

+244
-26
lines changed

.github/workflows/dispatch-k6-performance.yml

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ on:
5353
- 'tests/k6/tests/enduser/performance/enduser-search.js'
5454
- 'tests/k6/tests/graphql/performance/graphql-search.js'
5555
- 'tests/k6/tests/serviceowner/performance/create-transmissions.js'
56+
- 'tests/k6/tests/serviceowner/performance/serviceOwnerRandomSearch.js'
57+
- 'tests/k6/tests/enduser/performance/enduserRandomSearch.js'
5658

5759
run-name: ${{ inputs.tag }} ${{ inputs.vus }}/${{ inputs.duration }}/${{ inputs.parallelism }}
5860
jobs:

tests/k6/common/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@ export const tokenGeneratorEnv = __ENV.API_ENVIRONMENT == "yt01" ? "yt01" : "tt0
7070
export const baseUrlGraphql = baseUrls[__ENV.API_VERSION]["graphql"][__ENV.API_ENVIRONMENT];
7171

7272
export const sentinelValue = "dialogporten-e2e-sentinel";
73-
export const sentinelPerformanceValue = "dialogporten-e2e-sentinel-performance";
73+
export const sentinelPerformanceValue = "dialogporten-performance-sentinel";

tests/k6/common/k6-utils.js

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { uuidv4, randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
2+
export { URL } from 'https://jslib.k6.io/url/1.0.0/index.js';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import http from 'k6/http';
2+
import { randomItem, uuidv4, URL} from '../../../common/k6-utils.js';
3+
import { getEndUserTokens } from '../../../common/token.js';
4+
import { expect, expectStatusFor } from "../../../common/testimports.js";
5+
import { describe } from '../../../common/describe.js';
6+
import { baseUrlEndUser } from '../../../common/config.js';
7+
const traceCalls = (__ENV.traceCalls ?? 'false') === 'true';
8+
const defaultNumberOfEndUsers = (__ENV.NUMBER_OF_ENDUSERS ?? 2799); // Max number of endusers from altinn-testtools now.
9+
10+
const texts = [ "påkrevd", "rapportering", "sammendrag", "Utvidet Status", "ingen HTML-støtte", "et eller annet", "Skjema", "Skjema for rapportering av et eller annet", "Maks 200 tegn", "liste" ];
11+
const texts_no_hit = [ "sjøvegan", "larvik", "kvalsund", "jøssheim", "sørli"];
12+
const resources = [
13+
"ttd-dialogporten-performance-test-01",
14+
"ttd-dialogporten-performance-test-02",
15+
"ttd-dialogporten-performance-test-03",
16+
"ttd-dialogporten-performance-test-04",
17+
"ttd-dialogporten-performance-test-05",
18+
"ttd-dialogporten-performance-test-06",
19+
"ttd-dialogporten-performance-test-07",
20+
"ttd-dialogporten-performance-test-08",
21+
"ttd-dialogporten-performance-test-09",
22+
"ttd-dialogporten-performance-test-10"
23+
];
24+
25+
// Available enduser filters:
26+
// org, party, serviceResource, extendedStatus, externalReference, status, createdAfter, createdBefore, updatedAfter, updatedBefore, dueAfter, dueBefore, Search, searchLanguageCode, orderBy, limit
27+
28+
const filter_combos = [
29+
{label: "serviceresource", filters: ["serviceResource"]},
30+
{label: "serviceresource-createdafter", filters: ["serviceResource", "createdAfter"]},
31+
{label: "serviceresource-createdbefore", filters: ["serviceResource", "createdBefore"]},
32+
{label: "party-createdafter", filters: ["party", "createdAfter"]},
33+
{label: "party-createdbefore", filters: ["party", "createdBefore"]},
34+
{label: "search-party-createdafter", filters: ["Search", "party", "createdAfter"]},
35+
{label: "search-serviceresource-createdafter", filters: ["Search", "serviceResource", "createdAfter"]},
36+
{label: "search-serviceresource-createdafter-nohit", filters: ["Search", "serviceResource", "createdAfter"]},
37+
{label: "search-serviceresource", filters: ["Search", "serviceresource"]},
38+
{label: "search-party-createdafter", filters: ["Search", "party", "createdAfter"]},
39+
{label: "search-party-createdafter-nohit", filters: ["Search", "party", "createdAfter"]},
40+
{label: "search-party", filters: ["Search", "party"]},
41+
{label: "party", filters: ["party"]},
42+
43+
];
44+
45+
export let options = {
46+
setupTimeout: '10m',
47+
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
48+
thresholds: {
49+
checks: ['rate>=1.0']
50+
}
51+
};
52+
53+
for (var filter of filter_combos) {
54+
options.thresholds[[`http_req_duration{name:${filter.label}}`]] = [];
55+
options.thresholds[[`http_req_failed{name:${filter.label}}`]] = ['rate<=0.0'];
56+
}
57+
58+
function get_query_params(endUser) {
59+
var search_params = {};
60+
var filter_combo = randomItem(filter_combos);
61+
var label = filter_combo.label
62+
for (var filter of filter_combo.filters) {
63+
search_params[filter] = get_filter_value(filter, label, endUser)
64+
}
65+
return [search_params, label];
66+
}
67+
68+
function get_filter_value(filter, label, endUser) {
69+
switch (filter) {
70+
case "serviceResource": return "urn:altinn:resource:" +randomItem(resources);
71+
case "party": return "urn:altinn:person:identifier-no:" +endUser;
72+
case "status": return "New";
73+
case "deleted": return "Exclude";
74+
case "createdAfter": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
75+
case "createdBefore": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
76+
case "Search": return label.includes("nohit") ? randomItem(texts_no_hit) : randomItem(texts);
77+
default: return "urn:altinn:resource:" +randomItem(resources);
78+
}
79+
}
80+
81+
export function setup(numberOfEndUsers = defaultNumberOfEndUsers) {
82+
const tokenOptions = {
83+
scopes: "digdir:dialogporten"
84+
}
85+
if (numberOfEndUsers === null) {
86+
numberOfEndUsers = defaultNumberOfEndUsers;
87+
}
88+
const endusers = getEndUserTokens(numberOfEndUsers, tokenOptions);
89+
return endusers
90+
}
91+
92+
export default function(data) {
93+
const endUser = randomItem(Object.keys(data));
94+
const [queryParams, label] = get_query_params(endUser);
95+
const token = data[endUser];
96+
const traceparent = uuidv4();
97+
const paramsWithToken = {
98+
headers: {
99+
Authorization: "Bearer " + token,
100+
traceparent: traceparent,
101+
Accept: 'application/json',
102+
'User-Agent': 'dialogporten-k6',
103+
},
104+
tags: { name: label }
105+
}
106+
107+
if (traceCalls) {
108+
paramsWithToken.tags.traceparent = traceparent;
109+
}
110+
111+
const url = new URL(baseUrlEndUser + 'dialogs');
112+
for (const key in queryParams) {
113+
url.searchParams.append(key, queryParams[key]);
114+
}
115+
116+
describe('Perform enduser dialog list', () => {
117+
let r = http.get(url.toString(), paramsWithToken);
118+
expectStatusFor(r).to.equal(200);
119+
expect(r, 'response').to.have.validJsonBody();
120+
return r
121+
});
122+
}
123+
124+
125+

tests/k6/tests/performancetest_data/01-create-dialog.js

+1-25
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {default as createDialogPayload} from "../serviceowner/testdata/01-create-dialog.js"
22
import { sentinelPerformanceValue } from "../../common/config.js";
33

4-
const ACTIVITY_TYPE_INFORMATION = 'Information';
5-
64
function cleanUp(originalPayload) {
75
if (!originalPayload || typeof originalPayload !== 'object') {
86
throw new Error('Invalid payload');
@@ -12,29 +10,7 @@ function cleanUp(originalPayload) {
1210
...originalPayload,
1311
searchTags: [...(originalPayload.searchTags || []), { "value": sentinelPerformanceValue }]
1412
};
15-
const { visibleFrom, ...payloadWithoutVisibleFrom } = payload;
16-
17-
const activities = payload.activities?.map(activity => {
18-
if (activity.type !== ACTIVITY_TYPE_INFORMATION) {
19-
return activity;
20-
}
21-
22-
const { performedBy, ...rest } = activity;
23-
const { actorId, ...performedByRest } = performedBy;
24-
25-
return {
26-
...rest,
27-
performedBy: {
28-
...performedByRest,
29-
actorName: "some name"
30-
}
31-
};
32-
}) ?? [];
33-
34-
return {
35-
...payloadWithoutVisibleFrom,
36-
activities
37-
};
13+
return payload
3814
}
3915

4016
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import http from 'k6/http';
2+
import { serviceOwners, endUsers } from '../../performancetest_common/readTestdata.js';
3+
import { randomItem, uuidv4, URL} from '../../../common/k6-utils.js';
4+
import { expect, expectStatusFor } from "../../../common/testimports.js";
5+
import { describe } from '../../../common/describe.js';
6+
import { baseUrlServiceOwner } from '../../../common/config.js';
7+
import { getEnterpriseToken } from '../../performancetest_common/getTokens.js';
8+
const traceCalls = (__ENV.traceCalls ?? 'false') === 'true';
9+
10+
const texts = [ "påkrevd", "rapportering", "sammendrag", "Utvidet Status", "ingen HTML-støtte", "et eller annet", "Skjema", "Skjema for rapportering av et eller annet", "Maks 200 tegn", "liste" ];
11+
const texts_no_hit = [ "sjøvegan", "larvik", "kvalsund", "jøssheim", "sørli"];
12+
const resources = [
13+
"ttd-dialogporten-performance-test-01",
14+
"ttd-dialogporten-performance-test-02",
15+
"ttd-dialogporten-performance-test-03",
16+
"ttd-dialogporten-performance-test-04",
17+
"ttd-dialogporten-performance-test-05",
18+
"ttd-dialogporten-performance-test-06",
19+
"ttd-dialogporten-performance-test-07",
20+
"ttd-dialogporten-performance-test-08",
21+
"ttd-dialogporten-performance-test-09",
22+
"ttd-dialogporten-performance-test-10"
23+
];
24+
25+
// Available enduser filters:
26+
// party, endUser, serviceResource, status, deleted, createdAfter, createdBefore, updatedAfter, updatedBefore, dueAfter, dueBefore, visibleAfter, visibleBefore, Search, searchLanguageCode, orderBy, limit
27+
28+
const filter_combos = [
29+
{label: "enduser", filters: ["endUser"]},
30+
{label: "enduser-serviceresource", filters: ["endUser", "serviceResource"]},
31+
{label: "enduser-serviceresource-createdafter", filters: ["endUser", "serviceResource", "createdAfter"]},
32+
{label: "enduser-serviceresource-createdbefore", filters: ["endUser", "serviceResource", "createdBefore"]},
33+
{label: "enduser-createdafter", filters: ["endUser", "createdAfter"]},
34+
{label: "enduser-createdbefore", filters: ["endUser", "createdBefore"]},
35+
{label: "search-enduser-createdafter", filters: ["Search", "endUser", "createdAfter"]},
36+
{label: "search-createdafter", filters: ["Search", "createdAfter"]},
37+
{label: "search-serviceresource-enduser-createdafter", filters: ["Search", "serviceResource", "endUser", "createdAfter"]},
38+
{label: "search-enduser-createdafter-nohit", filters: ["Search", "endUser", "createdAfter"]},
39+
{label: "search", filters: ["Search"]},
40+
41+
];
42+
43+
const orgNos = ["713431400"]
44+
45+
46+
export let options = {
47+
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
48+
thresholds: {
49+
checks: ['rate>=1.0']
50+
}
51+
};
52+
53+
for (var filter of filter_combos) {
54+
options.thresholds[[`http_req_duration{name:${filter.label}}`]] = [];
55+
options.thresholds[[`http_req_failed{name:${filter.label}}`]] = ['rate<=0.0'];
56+
}
57+
58+
function get_query_params() {
59+
var search_params = {};
60+
var filter_combo = randomItem(filter_combos);
61+
var label = filter_combo.label
62+
for (var filter of filter_combo.filters) {
63+
search_params[filter] = get_filter_value(filter, label)
64+
}
65+
return [search_params, label];
66+
}
67+
68+
function get_filter_value(filter, label) {
69+
switch (filter) {
70+
case "endUser": return "urn:altinn:person:identifier-no:" +randomItem(endUsers).ssn;
71+
case "serviceResource": return "urn:altinn:resource:" +randomItem(resources);
72+
case "party": return "urn:altinn:organization:identifier-no:" +randomItem(orgNos);
73+
case "status": return "New";
74+
case "deleted": return "Exclude";
75+
case "createdAfter": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
76+
case "createdBefore": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
77+
case "Search": return label.includes("nohit") ? randomItem(texts_no_hit) : randomItem(texts);
78+
default: return "urn:altinn:resource:" +randomItem(resources);
79+
}
80+
}
81+
82+
export default function() {
83+
const [queryParams, label] = get_query_params();
84+
const serviceowner = serviceOwners[0];
85+
const traceparent = uuidv4();
86+
const paramsWithToken = {
87+
headers: {
88+
Authorization: "Bearer " + getEnterpriseToken(serviceowner),
89+
traceparent: traceparent,
90+
Accept: 'application/json',
91+
'User-Agent': 'dialogporten-k6',
92+
},
93+
tags: { name: label }
94+
}
95+
96+
if (traceCalls) {
97+
paramsWithToken.tags.traceparent = traceparent;
98+
}
99+
100+
const url = new URL(baseUrlServiceOwner + 'dialogs');
101+
for (const key in queryParams) {
102+
url.searchParams.append(key, queryParams[key]);
103+
}
104+
105+
describe('Perform serviceowner dialog list', () => {
106+
let r = http.get(url.toString(), paramsWithToken);
107+
expectStatusFor(r).to.equal(200);
108+
expect(r, 'response').to.have.validJsonBody();
109+
return r
110+
});
111+
}
112+
113+
114+

0 commit comments

Comments
 (0)