Skip to content

Commit

Permalink
chore(performance): Make improved tests for search (#1983)
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
dagfinno authored Mar 3, 2025
1 parent 224e837 commit 9412a85
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/dispatch-k6-performance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ on:
- 'tests/k6/tests/enduser/performance/enduser-search.js'
- 'tests/k6/tests/graphql/performance/graphql-search.js'
- 'tests/k6/tests/serviceowner/performance/create-transmissions.js'
- 'tests/k6/tests/serviceowner/performance/serviceOwnerRandomSearch.js'
- 'tests/k6/tests/enduser/performance/enduserRandomSearch.js'

run-name: ${{ inputs.tag }} ${{ inputs.vus }}/${{ inputs.duration }}/${{ inputs.parallelism }}
jobs:
Expand Down
2 changes: 1 addition & 1 deletion tests/k6/common/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ export const tokenGeneratorEnv = __ENV.API_ENVIRONMENT == "yt01" ? "yt01" : "tt0
export const baseUrlGraphql = baseUrls[__ENV.API_VERSION]["graphql"][__ENV.API_ENVIRONMENT];

export const sentinelValue = "dialogporten-e2e-sentinel";
export const sentinelPerformanceValue = "dialogporten-e2e-sentinel-performance";
export const sentinelPerformanceValue = "dialogporten-performance-sentinel";
1 change: 1 addition & 0 deletions tests/k6/common/k6-utils.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { uuidv4, randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
export { URL } from 'https://jslib.k6.io/url/1.0.0/index.js';
125 changes: 125 additions & 0 deletions tests/k6/tests/enduser/performance/enduserRandomSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import http from 'k6/http';
import { randomItem, uuidv4, URL} from '../../../common/k6-utils.js';
import { getEndUserTokens } from '../../../common/token.js';
import { expect, expectStatusFor } from "../../../common/testimports.js";
import { describe } from '../../../common/describe.js';
import { baseUrlEndUser } from '../../../common/config.js';
const traceCalls = (__ENV.traceCalls ?? 'false') === 'true';
const defaultNumberOfEndUsers = (__ENV.NUMBER_OF_ENDUSERS ?? 2799); // Max number of endusers from altinn-testtools now.

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" ];
const texts_no_hit = [ "sjøvegan", "larvik", "kvalsund", "jøssheim", "sørli"];
const resources = [
"ttd-dialogporten-performance-test-01",
"ttd-dialogporten-performance-test-02",
"ttd-dialogporten-performance-test-03",
"ttd-dialogporten-performance-test-04",
"ttd-dialogporten-performance-test-05",
"ttd-dialogporten-performance-test-06",
"ttd-dialogporten-performance-test-07",
"ttd-dialogporten-performance-test-08",
"ttd-dialogporten-performance-test-09",
"ttd-dialogporten-performance-test-10"
];

// Available enduser filters:
// org, party, serviceResource, extendedStatus, externalReference, status, createdAfter, createdBefore, updatedAfter, updatedBefore, dueAfter, dueBefore, Search, searchLanguageCode, orderBy, limit

const filter_combos = [
{label: "serviceresource", filters: ["serviceResource"]},
{label: "serviceresource-createdafter", filters: ["serviceResource", "createdAfter"]},
{label: "serviceresource-createdbefore", filters: ["serviceResource", "createdBefore"]},
{label: "party-createdafter", filters: ["party", "createdAfter"]},
{label: "party-createdbefore", filters: ["party", "createdBefore"]},
{label: "search-party-createdafter", filters: ["Search", "party", "createdAfter"]},
{label: "search-serviceresource-createdafter", filters: ["Search", "serviceResource", "createdAfter"]},
{label: "search-serviceresource-createdafter-nohit", filters: ["Search", "serviceResource", "createdAfter"]},
{label: "search-serviceresource", filters: ["Search", "serviceresource"]},
{label: "search-party-createdafter", filters: ["Search", "party", "createdAfter"]},
{label: "search-party-createdafter-nohit", filters: ["Search", "party", "createdAfter"]},
{label: "search-party", filters: ["Search", "party"]},
{label: "party", filters: ["party"]},

];

export let options = {
setupTimeout: '10m',
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
thresholds: {
checks: ['rate>=1.0']
}
};

for (var filter of filter_combos) {
options.thresholds[[`http_req_duration{name:${filter.label}}`]] = [];
options.thresholds[[`http_req_failed{name:${filter.label}}`]] = ['rate<=0.0'];
}

function get_query_params(endUser) {
var search_params = {};
var filter_combo = randomItem(filter_combos);
var label = filter_combo.label
for (var filter of filter_combo.filters) {
search_params[filter] = get_filter_value(filter, label, endUser)
}
return [search_params, label];
}

function get_filter_value(filter, label, endUser) {
switch (filter) {
case "serviceResource": return "urn:altinn:resource:" +randomItem(resources);
case "party": return "urn:altinn:person:identifier-no:" +endUser;
case "status": return "New";
case "deleted": return "Exclude";
case "createdAfter": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
case "createdBefore": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
case "Search": return label.includes("nohit") ? randomItem(texts_no_hit) : randomItem(texts);
default: return "urn:altinn:resource:" +randomItem(resources);
}
}

export function setup(numberOfEndUsers = defaultNumberOfEndUsers) {
const tokenOptions = {
scopes: "digdir:dialogporten"
}
if (numberOfEndUsers === null) {
numberOfEndUsers = defaultNumberOfEndUsers;
}
const endusers = getEndUserTokens(numberOfEndUsers, tokenOptions);
return endusers
}

export default function(data) {
const endUser = randomItem(Object.keys(data));
const [queryParams, label] = get_query_params(endUser);
const token = data[endUser];
const traceparent = uuidv4();
const paramsWithToken = {
headers: {
Authorization: "Bearer " + token,
traceparent: traceparent,
Accept: 'application/json',
'User-Agent': 'dialogporten-k6',
},
tags: { name: label }
}

if (traceCalls) {
paramsWithToken.tags.traceparent = traceparent;
}

const url = new URL(baseUrlEndUser + 'dialogs');
for (const key in queryParams) {
url.searchParams.append(key, queryParams[key]);
}

describe('Perform enduser dialog list', () => {
let r = http.get(url.toString(), paramsWithToken);
expectStatusFor(r).to.equal(200);
expect(r, 'response').to.have.validJsonBody();
return r
});
}



26 changes: 1 addition & 25 deletions tests/k6/tests/performancetest_data/01-create-dialog.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {default as createDialogPayload} from "../serviceowner/testdata/01-create-dialog.js"
import { sentinelPerformanceValue } from "../../common/config.js";

const ACTIVITY_TYPE_INFORMATION = 'Information';

function cleanUp(originalPayload) {
if (!originalPayload || typeof originalPayload !== 'object') {
throw new Error('Invalid payload');
Expand All @@ -12,29 +10,7 @@ function cleanUp(originalPayload) {
...originalPayload,
searchTags: [...(originalPayload.searchTags || []), { "value": sentinelPerformanceValue }]
};
const { visibleFrom, ...payloadWithoutVisibleFrom } = payload;

const activities = payload.activities?.map(activity => {
if (activity.type !== ACTIVITY_TYPE_INFORMATION) {
return activity;
}

const { performedBy, ...rest } = activity;
const { actorId, ...performedByRest } = performedBy;

return {
...rest,
performedBy: {
...performedByRest,
actorName: "some name"
}
};
}) ?? [];

return {
...payloadWithoutVisibleFrom,
activities
};
return payload
}

/**
Expand Down
114 changes: 114 additions & 0 deletions tests/k6/tests/serviceowner/performance/serviceOwnerRandomSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import http from 'k6/http';
import { serviceOwners, endUsers } from '../../performancetest_common/readTestdata.js';
import { randomItem, uuidv4, URL} from '../../../common/k6-utils.js';
import { expect, expectStatusFor } from "../../../common/testimports.js";
import { describe } from '../../../common/describe.js';
import { baseUrlServiceOwner } from '../../../common/config.js';
import { getEnterpriseToken } from '../../performancetest_common/getTokens.js';
const traceCalls = (__ENV.traceCalls ?? 'false') === 'true';

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" ];
const texts_no_hit = [ "sjøvegan", "larvik", "kvalsund", "jøssheim", "sørli"];
const resources = [
"ttd-dialogporten-performance-test-01",
"ttd-dialogporten-performance-test-02",
"ttd-dialogporten-performance-test-03",
"ttd-dialogporten-performance-test-04",
"ttd-dialogporten-performance-test-05",
"ttd-dialogporten-performance-test-06",
"ttd-dialogporten-performance-test-07",
"ttd-dialogporten-performance-test-08",
"ttd-dialogporten-performance-test-09",
"ttd-dialogporten-performance-test-10"
];

// Available enduser filters:
// party, endUser, serviceResource, status, deleted, createdAfter, createdBefore, updatedAfter, updatedBefore, dueAfter, dueBefore, visibleAfter, visibleBefore, Search, searchLanguageCode, orderBy, limit

const filter_combos = [
{label: "enduser", filters: ["endUser"]},
{label: "enduser-serviceresource", filters: ["endUser", "serviceResource"]},
{label: "enduser-serviceresource-createdafter", filters: ["endUser", "serviceResource", "createdAfter"]},
{label: "enduser-serviceresource-createdbefore", filters: ["endUser", "serviceResource", "createdBefore"]},
{label: "enduser-createdafter", filters: ["endUser", "createdAfter"]},
{label: "enduser-createdbefore", filters: ["endUser", "createdBefore"]},
{label: "search-enduser-createdafter", filters: ["Search", "endUser", "createdAfter"]},
{label: "search-createdafter", filters: ["Search", "createdAfter"]},
{label: "search-serviceresource-enduser-createdafter", filters: ["Search", "serviceResource", "endUser", "createdAfter"]},
{label: "search-enduser-createdafter-nohit", filters: ["Search", "endUser", "createdAfter"]},
{label: "search", filters: ["Search"]},

];

const orgNos = ["713431400"]


export let options = {
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
thresholds: {
checks: ['rate>=1.0']
}
};

for (var filter of filter_combos) {
options.thresholds[[`http_req_duration{name:${filter.label}}`]] = [];
options.thresholds[[`http_req_failed{name:${filter.label}}`]] = ['rate<=0.0'];
}

function get_query_params() {
var search_params = {};
var filter_combo = randomItem(filter_combos);
var label = filter_combo.label
for (var filter of filter_combo.filters) {
search_params[filter] = get_filter_value(filter, label)
}
return [search_params, label];
}

function get_filter_value(filter, label) {
switch (filter) {
case "endUser": return "urn:altinn:person:identifier-no:" +randomItem(endUsers).ssn;
case "serviceResource": return "urn:altinn:resource:" +randomItem(resources);
case "party": return "urn:altinn:organization:identifier-no:" +randomItem(orgNos);
case "status": return "New";
case "deleted": return "Exclude";
case "createdAfter": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
case "createdBefore": return new Date(Date.now() - 7*24*60*60*1000).toISOString();
case "Search": return label.includes("nohit") ? randomItem(texts_no_hit) : randomItem(texts);
default: return "urn:altinn:resource:" +randomItem(resources);
}
}

export default function() {
const [queryParams, label] = get_query_params();
const serviceowner = serviceOwners[0];
const traceparent = uuidv4();
const paramsWithToken = {
headers: {
Authorization: "Bearer " + getEnterpriseToken(serviceowner),
traceparent: traceparent,
Accept: 'application/json',
'User-Agent': 'dialogporten-k6',
},
tags: { name: label }
}

if (traceCalls) {
paramsWithToken.tags.traceparent = traceparent;
}

const url = new URL(baseUrlServiceOwner + 'dialogs');
for (const key in queryParams) {
url.searchParams.append(key, queryParams[key]);
}

describe('Perform serviceowner dialog list', () => {
let r = http.get(url.toString(), paramsWithToken);
expectStatusFor(r).to.equal(200);
expect(r, 'response').to.have.validJsonBody();
return r
});
}



0 comments on commit 9412a85

Please sign in to comment.