Skip to content

Commit

Permalink
feat(performance): Expands search for serviceowners, improved tracing…
Browse files Browse the repository at this point in the history
… and logging (#1439)

Implements more GET testcalls to serviceowner apis and improves tracing
and logging

## Description

<!--- Describe your changes in detail -->

## Related Issue(s)

- #1326 

## 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)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

- **New Features**
- Introduced a `sentinelPerformanceValue` for enhanced performance
tracking.
- Added flexibility to performance tests by implementing
`isSingleUserMode` for better user scenario handling.

- **Improvements**
- Enhanced logging and traceability in dialog creation and purging
processes.
  - Expanded performance thresholds for more detailed monitoring.
- Updated functions to accept dynamic GET request functions, improving
modularity.

- **Bug Fixes**
- Improved error handling and conditions for single vs. multi-user modes
in various performance test scripts.

- **Documentation**
- Updated comments for clarity regarding options and parameters in
several scripts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
dagfinno and coderabbitai[bot] authored Nov 12, 2024
1 parent 0972243 commit b1d6eaf
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 37 deletions.
1 change: 1 addition & 0 deletions tests/k6/common/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,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";
7 changes: 5 additions & 2 deletions tests/k6/tests/enduser/performance/enduser-search.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { enduserSearch } from '../../performancetest_common/simpleSearch.js'
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { endUsersWithTokens } from '../../performancetest_common/readTestdata.js';
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';

export let options = {
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
Expand All @@ -19,8 +20,10 @@ export let options = {
export default function() {
if (!endUsersWithTokens || endUsersWithTokens.length === 0) {
throw new Error('No end users loaded for testing');
}
if ((options.vus === undefined || options.vus === 1) && (options.iterations === undefined || options.iterations === 1)) {
}

const isSingleUserMode = (options.vus ?? 1) === 1 && (options.iterations ?? 1) === 1 && (options.duration ?? 0) === 0;
if (isSingleUserMode) {
enduserSearch(endUsersWithTokens[0]);
}
else {
Expand Down
6 changes: 4 additions & 2 deletions tests/k6/tests/graphql/performance/graphql-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
* Run: k6 run tests/k6/tests/graphql/performance/graphql-search.js --vus 1 --iterations 1 -e env=yt01
*/

import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { endUsersWithTokens as endUsers } from '../../performancetest_common/readTestdata.js';
import { graphqlSearch } from "../../performancetest_common/simpleSearch.js";


/**
* The options object for configuring the performance test for GraphQL search.
*
Expand All @@ -26,7 +27,8 @@ export default function() {
if (!endUsers || endUsers.length === 0) {
throw new Error('No end users loaded for testing');
}
if ((options.vus === undefined || options.vus === 1) && (options.iterations === undefined || options.iterations === 1)) {
const isSingleUserMode = (options.vus ?? 1) === 1 && (options.iterations ?? 1) === 1 && (options.duration ?? 0) === 0;
if (isSingleUserMode) {
graphqlSearch(endUsers[0]);
}
else {
Expand Down
16 changes: 11 additions & 5 deletions tests/k6/tests/performancetest_common/createDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import dialogToInsert from "../performancetest_data/01-create-dialog.js";
* @param {Object} endUser - The end user object.
*/
export function createDialog(serviceOwner, endUser) {
var traceparent = uuidv4();
var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token,
traceparent: uuidv4()
traceparent: traceparent
},
tags: { name: 'create dialog' }
tags: { name: 'create dialog', traceparent: traceparent, enduser: endUser.ssn }
};

describe('create dialog', () => {
Expand All @@ -35,12 +36,14 @@ export function createDialog(serviceOwner, endUser) {
* @param {Object} serviceOwner - The service owner object.
* @param {Object} endUser - The end user object.
*/
export function createAndRemoveDialog(serviceOwner, endUser) {
export function createAndRemoveDialog(serviceOwner, endUser) {
var traceparent = uuidv4();
var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token
Authorization: "Bearer " + serviceOwner.token,
traceparent: traceparent
},
tags: { name: 'create dialog' }
tags: { name: 'create dialog', traceparent: traceparent, enduser: endUser.ssn }
}

let dialogId = 0;
Expand All @@ -52,7 +55,10 @@ export function createAndRemoveDialog(serviceOwner, endUser) {
});

describe('remove dialog', () => {
traceparent = uuidv4();
paramsWithToken.tags.name = 'remove dialog';
paramsWithToken.tags.traceparent = traceparent;
paramsWithToken.headers.traceparent = traceparent
if (dialogId) {
let r = purgeSO('dialogs/' + dialogId, paramsWithToken);
expect(r.status, 'response status').to.equal(204);
Expand Down
40 changes: 23 additions & 17 deletions tests/k6/tests/performancetest_common/simpleSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ import { getGraphqlParty } from '../performancetest_data/graphql-search.js';
* @param {Object} paramsWithToken - The parameters with token.
* @returns {void}
*/
function retrieveDialogContent(response, paramsWithToken) {
function retrieveDialogContent(response, paramsWithToken, getFunction = getEU) {
const items = response.json().items;
if (!items?.length) return;

const dialogId = items[0].id;
if (!dialogId) return;

getContent(dialogId, paramsWithToken, 'get dialog');
getContentChain(dialogId, paramsWithToken, 'get dialog activities', 'get dialog activity', '/activities/')
getContentChain(dialogId, paramsWithToken, 'get seenlogs', 'get seenlog', '/seenlog/')
getContent(dialogId, paramsWithToken, 'get labellog', '/labellog');
getContentChain(dialogId, paramsWithToken, 'get transmissions', 'get transmission', '/transmissions/')
getContent(dialogId, paramsWithToken, 'get dialog', '', getFunction);
getContentChain(dialogId, paramsWithToken, 'get dialog activities', 'get dialog activity', '/activities/', getFunction);
getContentChain(dialogId, paramsWithToken, 'get seenlogs', 'get seenlog', '/seenlog/', getFunction);
if (getFunction == getEU) {
getContent(dialogId, paramsWithToken, 'get labellog', '/labellog', getFunction);
}
getContentChain(dialogId, paramsWithToken, 'get transmissions', 'get transmission', '/transmissions/', getFunction);
}

/**
Expand Down Expand Up @@ -61,12 +63,12 @@ export function enduserSearch(enduser) {
* @param {string} path - The path to append to the URL. Can be empty or /labellog.
* @returns {void}
*/
export function getContent(dialogId, paramsWithToken, tag, path = '') {
export function getContent(dialogId, paramsWithToken, tag, path = '', getFunction = getEU) {
const listParams = {
...paramsWithToken,
tags: { ...paramsWithToken.tags, name: tag }
};
getUrl('dialogs/' + dialogId + path, listParams);
getUrl('dialogs/' + dialogId + path, listParams, getFunction);
}

/**
Expand All @@ -78,19 +80,19 @@ export function getContent(dialogId, paramsWithToken, tag, path = '') {
* @param {string} endpoint - The endpoint to append to the URL.
* @returns {void}
*/
export function getContentChain(dialogId, paramsWithToken, tag, subtag, endpoint) {
export function getContentChain(dialogId, paramsWithToken, tag, subtag, endpoint, getFunction = getEU) {
const listParams = {
...paramsWithToken,
tags: { ...paramsWithToken.tags, name: tag }
};
let d = getUrl('dialogs/' + dialogId + endpoint, listParams);
let d = getUrl('dialogs/' + dialogId + endpoint, listParams, getFunction);
let json = d.json();
if (json.length > 0) {
const detailParams = {
...paramsWithToken,
tags: { ...paramsWithToken.tags, name: subtag }
};
getUrl('dialogs/' + dialogId + endpoint + randomItem(json).id, detailParams);
getUrl('dialogs/' + dialogId + endpoint + randomItem(json).id, detailParams, getFunction);
}
}

Expand All @@ -100,8 +102,8 @@ export function getContentChain(dialogId, paramsWithToken, tag, subtag, endpoint
* @param {Object} paramsWithToken - The parameters with token.
* @returns {Object} The response object.
*/
export function getUrl(url, paramsWithToken) {
let r = getEU(url, paramsWithToken);
export function getUrl(url, paramsWithToken, getFunction = getEU) {
let r = getFunction(url, paramsWithToken);
expectStatusFor(r).to.equal(200);
expect(r, 'response').to.have.validJsonBody();
return r;
Expand All @@ -114,12 +116,14 @@ export function getUrl(url, paramsWithToken) {
* @returns {void}
*/
export function graphqlSearch(enduser) {
let traceparent = uuidv4();
let paramsWithToken = {
headers: {
Authorization: "Bearer " + enduser.token,
traceparent: uuidv4()
traceparent: traceparent,
'User-Agent': 'dialogporten-k6-graphql-search'
},
tags: { name: 'graphql search' }
tags: { name: 'graphql search', traceparent: traceparent }
};
describe('Perform graphql dialog list', () => {
let r = postGQ(getGraphqlParty(enduser.ssn), paramsWithToken);
Expand All @@ -134,12 +138,13 @@ export function graphqlSearch(enduser) {
* @param {*} enduser
*/
export function serviceownerSearch(serviceowner, enduser, tag_name) {
let traceparent = uuidv4();
let paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceowner.token,
traceparent: uuidv4()
traceparent: traceparent
},
tags: { name: tag_name }
tags: { name: tag_name, traceparent: traceparent, enduser: enduser.ssn }
}

let enduserid = encodeURIComponent(`urn:altinn:person:identifier-no:${enduser.ssn}`);
Expand All @@ -149,5 +154,6 @@ export function serviceownerSearch(serviceowner, enduser, tag_name) {
let r = getSO('dialogs' + defaultFilter, paramsWithToken);
expectStatusFor(r).to.equal(200);
expect(r, 'response').to.have.validJsonBody();
retrieveDialogContent(r, paramsWithToken, getSO);
});
}
6 changes: 5 additions & 1 deletion tests/k6/tests/performancetest_data/01-create-dialog.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {default as createDialogPayload} from "../serviceowner/testdata/01-create-dialog.js"
import { sentinelPerformanceValue } from "../../common/config.js";

const ACTIVITY_TYPE_INFORMATION = 'Information';

Expand All @@ -7,7 +8,10 @@ function cleanUp(originalPayload) {
throw new Error('Invalid payload');
}

const payload = { ...originalPayload };
const payload = {
...originalPayload,
searchTags: [...(originalPayload.searchTags || []), { "value": sentinelPerformanceValue }]
};
const { visibleFrom, ...payloadWithoutVisibleFrom } = payload;

const activities = payload.activities?.map(activity => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
org,orgno,scopes,resource
digdir,991825827,digdir:dialogporten.serviceprovider,super-simple-service
digdir,991825827,digdir:dialogporten.serviceprovider digdir:dialogporten.serviceprovider.search,super-simple-service
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Performance test for creating dialogs and searching dialogs.
* Run: k6 run tests/k6/tests/scenarios/performance/create-dialog-and-search.js -e env=yt01 -e svus=1 -e evus=1 -e duration=1m
*/
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { enduserSearch } from '../../performancetest_common/simpleSearch.js';
import { createDialog } from '../../performancetest_common/createDialog.js';
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
Expand Down
5 changes: 3 additions & 2 deletions tests/k6/tests/serviceowner/performance/create-dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Performance test for creating a dialog
* Run: k6 run tests/k6/tests/serviceowner/performance/create-dialog.js --vus 1 --iterations 1
*/
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { createDialog } from '../../performancetest_common/createDialog.js';
import { serviceOwners, endUsers } from '../../performancetest_common/readTestdata.js';
Expand All @@ -19,7 +19,8 @@ export default function() {
if (!serviceOwners || serviceOwners.length === 0) {
throw new Error('No service owners loaded for testing');
}
if ((options.vus === undefined || options.vus === 1) && (options.iterations === undefined || options.iterations === 1)) {
const isSingleUserMode = (options.vus ?? 1) === 1 && (options.iterations ?? 1) === 1 && (options.duration ?? 0) === 0;
if (isSingleUserMode) {
createDialog(serviceOwners[0], endUsers[0]);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Performance test for creating and removing a dialog
* Run: k6 run tests/k6/tests/serviceowner/performance/create-remove-dialog.js --vus 1 --iterations 1
*/
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { serviceOwners, endUsers } from "../../performancetest_common/readTestdata.js";
import { createAndRemoveDialog } from '../../performancetest_common/createDialog.js';
Expand All @@ -22,7 +22,9 @@ export default function() {
if (!serviceOwners || serviceOwners.length === 0) {
throw new Error('No service owners loaded for testing');
}
if ((options.vus === undefined || options.vus === 1) && (options.iterations === undefined || options.iterations === 1)) {

const isSingleUserMode = (options.vus ?? 1) === 1 && (options.iterations ?? 1) === 1 && (options.duration ?? 0) === 0;
if (isSingleUserMode) {
createAndRemoveDialog(serviceOwners[0], endUsers[0]);
}
else {
Expand Down
8 changes: 6 additions & 2 deletions tests/k6/tests/serviceowner/performance/purge-dialogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
*
* Run: k6 run tests/k6/tests/serviceowner/performance/purge-dialogs.js -e env=yt01
*/
import { uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { getSO, purgeSO } from '../../../common/request.js';
import { serviceOwners } from '../../performancetest_common/readTestdata.js';
import { expect, expectStatusFor } from "../../../common/testimports.js";
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { describe } from '../../../common/describe.js';
import { sentinelValue } from '../../../common/config.js';
import { sentinelPerformanceValue as sentinelValue } from '../../../common/config.js';

/**
* Retrieves the dialog ids to purge.
Expand All @@ -21,9 +22,12 @@ import { sentinelValue } from '../../../common/config.js';
* @returns {Array} - The dialog ids to purge.
*/
function getDialogs(serviceOwner) {
var traceparent = uuidv4();
console.log("Searching for dialogs to purge, tracevalue: " + traceparent);
var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token
Authorization: "Bearer " + serviceOwner.token,
traceparent: traceparent
}
}
let hasNextPage = false;
Expand Down
11 changes: 9 additions & 2 deletions tests/k6/tests/serviceowner/performance/serviceowner-search.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.1.0/index.js';
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { serviceownerSearch } from '../../performancetest_common/simpleSearch.js'
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { serviceOwners ,endUsersWithTokens } from '../../performancetest_common/readTestdata.js';
Expand All @@ -7,7 +7,14 @@ const tag_name = 'serviceowner search';

export let options = {
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
thresholds: getDefaultThresholds(['http_req_duration', 'http_reqs'],[tag_name])
thresholds: getDefaultThresholds(['http_req_duration', 'http_reqs'],[tag_name,
'get dialog',
'get dialog activities',
'get dialog activity',
'get seenlogs',
'get seenlog',
'get transmissions',
'get transmission'])
};

/**
Expand Down

0 comments on commit b1d6eaf

Please sign in to comment.