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

feat(performance): Refactoring and tracing #1489

Merged
merged 8 commits into from
Nov 20, 2024
Merged
4 changes: 3 additions & 1 deletion .github/workflows/workflow-run-k6-performance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ jobs:
- name: Run K6 tests (${{ inputs.testSuitePath }})
run: |
./tests/k6/tests/scripts/generate_tokens.sh ./tests/k6/tests/performancetest_data ${{ inputs.tokens }}
k6 run ${{ inputs.testSuitePath }} --quiet --log-output=stdout --include-system-env-vars --vus=${{ inputs.vus }} --duration=${{ inputs.duration }} --out=cloud
k6 run ${{ inputs.testSuitePath }} --quiet --log-output=stdout --include-system-env-vars \
--vus=${{ inputs.vus }} --duration=${{ inputs.duration }} --out=cloud --out csv=./results.csv
grep http_req_duration ./results.csv | sort --field-separator=',' --key=3 -nr | head -10
env:
API_ENVIRONMENT: ${{ inputs.environment }}
API_VERSION: ${{ inputs.apiVersion }}
Expand Down
11 changes: 7 additions & 4 deletions tests/k6/tests/enduser/performance/enduser-search.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
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';

const isSingleUserMode = (__ENV.isSingleUserMode ?? 'false') === 'true';
const traceCalls = (__ENV.traceCalls ?? 'false') === 'true';

export let options = {
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'p(99.5)', 'p(99.9)', 'count'],
Expand All @@ -22,12 +24,13 @@ export default function() {
throw new Error('No end users loaded for testing');
}

const isSingleUserMode = (options.vus ?? 1) === 1 && (options.iterations ?? 1) === 1 && (options.duration ?? 0) === 0;
if (isSingleUserMode) {
enduserSearch(endUsersWithTokens[0]);
enduserSearch(endUsersWithTokens[0], traceCalls);
}
else {
enduserSearch(randomItem(endUsersWithTokens));
for (let i = 0; i < endUsersWithTokens.length; i++) {
enduserSearch(endUsersWithTokens[i], traceCalls);
}
}
}

11 changes: 7 additions & 4 deletions tests/k6/tests/graphql/performance/graphql-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
* 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.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";

const isSingleUserMode = (__ENV.isSingleUserMode ?? 'false') === 'true';
const traceCalls = (__ENV.traceCalls ?? 'false') === 'true';


/**
* The options object for configuring the performance test for GraphQL search.
Expand All @@ -27,12 +29,13 @@ export default function() {
if (!endUsers || endUsers.length === 0) {
throw new Error('No end users loaded for testing');
}
const isSingleUserMode = (options.vus ?? 1) === 1 && (options.iterations ?? 1) === 1 && (options.duration ?? 0) === 0;
if (isSingleUserMode) {
graphqlSearch(endUsers[0]);
graphqlSearch(endUsers[0], traceCalls);
}
else {
graphqlSearch(randomItem(endUsers));
for (let i = 0; i < endUsers.length; i++) {
graphqlSearch(endUsers[i], traceCalls);
}
}
}

Expand Down
21 changes: 14 additions & 7 deletions tests/k6/tests/performancetest_common/createDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@ import dialogToInsert from "../performancetest_data/01-create-dialog.js";
* @param {Object} serviceOwner - The service owner object.
* @param {Object} endUser - The end user object.
*/
export function createDialog(serviceOwner, endUser) {
export function createDialog(serviceOwner, endUser, traceCalls) {
var traceparent = uuidv4();

var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token,
traceparent: traceparent
},
tags: { name: 'create dialog', traceparent: traceparent, enduser: endUser.ssn }
tags: { name: 'create dialog' }
};
if (traceCalls) {
paramsWithToken.tags.traceparent = traceparent;
paramsWithToken.tags.enduser = endUser.ssn;
}

describe('create dialog', () => {
let r = postSO('dialogs', dialogToInsert(endUser.ssn, endUser.resource), paramsWithToken);
Expand All @@ -36,19 +41,23 @@ 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, traceCalls) {
var traceparent = uuidv4();
var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token,
traceparent: traceparent
},
tags: { name: 'create dialog', traceparent: traceparent, enduser: endUser.ssn }
tags: { name: 'create dialog' }
}
if (traceCalls) {
paramsWithToken.tags.traceparent = traceparent;
paramsWithToken.tags.enduser = endUser.ssn;
}

let dialogId = 0;
describe('create dialog', () => {
paramsWithToken.tags.name = 'create dialog';
paramsWithToken.tags.name = 'create dialog';
let r = postSO('dialogs', dialogToInsert(endUser.ssn, endUser.resource), paramsWithToken);
expect(r.status, 'response status').to.equal(201);
dialogId = r.json();
Expand All @@ -57,8 +66,6 @@ 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
53 changes: 40 additions & 13 deletions tests/k6/tests/performancetest_common/simpleSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { describe } from '../../common/describe.js';
import { getEU, postGQ, getSO } from '../../common/request.js';
import { getGraphqlParty } from '../performancetest_data/graphql-search.js';


/**
* Retrieves the content for a dialog.
* Get dialog, dialog activities, seenlogs, labellog, and transmissions.
Expand All @@ -19,7 +18,6 @@ import { getGraphqlParty } from '../performancetest_data/graphql-search.js';
function retrieveDialogContent(response, paramsWithToken, getFunction = getEU) {
const items = response.json().items;
if (!items?.length) return;

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

Expand All @@ -32,18 +30,29 @@ function retrieveDialogContent(response, paramsWithToken, getFunction = getEU) {
getContentChain(dialogId, paramsWithToken, 'get transmissions', 'get transmission', '/transmissions/', getFunction);
}

function log(items, traceCalls, enduser) {
if (items?.length && traceCalls) {
console.log("Found " + items.length + " dialogs" + " for enduser " + enduser.ssn);
}
}
dagfinno marked this conversation as resolved.
Show resolved Hide resolved

/**
* Performs a enduser search.
* @param {Object} enduser - The end user.
* @returns {void}
*/
export function enduserSearch(enduser) {
export function enduserSearch(enduser, traceCalls) {
var traceparent = uuidv4();
let paramsWithToken = {
headers: {
Authorization: "Bearer " + enduser.token,
traceparent: uuidv4()
traceparent: traceparent
},
tags: { name: 'enduser search' }
tags: { name: 'enduser search' }
}
if (traceCalls) {
paramsWithToken.tags.traceparent = traceparent;
paramsWithToken.tags.enduser = enduser.ssn;
}
let defaultParty = "urn:altinn:person:identifier-no:" + enduser.ssn;
let defaultFilter = "?Party=" + defaultParty;
Expand All @@ -52,6 +61,7 @@ export function enduserSearch(enduser) {
expectStatusFor(r).to.equal(200);
expect(r, 'response').to.have.validJsonBody();
retrieveDialogContent(r, paramsWithToken);
log(r.json().items, traceCalls, enduser);
});
}

Expand All @@ -60,7 +70,8 @@ export function enduserSearch(enduser) {
* @param {string} dialogId - The dialog id.
* @param {Object} paramsWithToken - The parameters with token.
* @param {string} tag - Tagging the request.
* @param {string} path - The path to append to the URL. Can be empty or /labellog.
* @param {string} path - The path to append to the URL. Can be empty or /labellog.
* @param {function} getFunction - The get function to use.
* @returns {void}
*/
export function getContent(dialogId, paramsWithToken, tag, path = '', getFunction = getEU) {
Expand All @@ -77,7 +88,8 @@ export function getContent(dialogId, paramsWithToken, tag, path = '', getFunctio
* @param {Object} paramsWithToken - The parameters with token.
* @param {string} tag - Tagging the request.
* @param {string} subtag - Tagging the sub request.
* @param {string} endpoint - The endpoint to append to the URL.
* @param {string} endpoint - The endpoint to append to the URL.
* @param {function} getFunction - The get function to use.
* @returns {void}
*/
export function getContentChain(dialogId, paramsWithToken, tag, subtag, endpoint, getFunction = getEU) {
Expand All @@ -100,6 +112,7 @@ export function getContentChain(dialogId, paramsWithToken, tag, subtag, endpoint
* Performs a GET request to the specified URL with the provided parameters.
* @param {string} url - The URL to send the GET request to.
* @param {Object} paramsWithToken - The parameters with token.
* @param {function} getFunction - The get function to use.
* @returns {Object} The response object.
*/
export function getUrl(url, paramsWithToken, getFunction = getEU) {
Expand All @@ -115,36 +128,46 @@ export function getUrl(url, paramsWithToken, getFunction = getEU) {
* @param {Object} enduser - The enduser object containing the token.
* @returns {void}
*/
export function graphqlSearch(enduser) {
export function graphqlSearch(enduser, traceCalls) {
let traceparent = uuidv4();
let paramsWithToken = {
headers: {
Authorization: "Bearer " + enduser.token,
traceparent: traceparent,
'User-Agent': 'dialogporten-k6-graphql-search'
},
tags: { name: 'graphql search', traceparent: traceparent }
tags: { name: 'graphql search' }
};
if (traceCalls) {
paramsWithToken.tags.traceparent = traceparent;
paramsWithToken.tags.enduser = enduser.ssn;
}
describe('Perform graphql dialog list', () => {
let r = postGQ(getGraphqlParty(enduser.ssn), paramsWithToken);
expectStatusFor(r).to.equal(200);
expect(r, 'response').to.have.validJsonBody();
log(r.json().data.searchDialogs.items, traceCalls, enduser);
});
}

/**
* Performs a serviceowner search.
* @param {P} serviceowner
* @param {*} enduser
* @param {*} enduser
* @param {*} tag_name
*/
export function serviceownerSearch(serviceowner, enduser, tag_name) {
export function serviceownerSearch(serviceowner, enduser, tag_name, traceCalls, doSubqueries = true) {
let traceparent = uuidv4();
let paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceowner.token,
traceparent: traceparent
},
tags: { name: tag_name, traceparent: traceparent, enduser: enduser.ssn }
tags: { name: tag_name }
}

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

let enduserid = encodeURIComponent(`urn:altinn:person:identifier-no:${enduser.ssn}`);
Expand All @@ -154,6 +177,10 @@ 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);
if (doSubqueries) {
retrieveDialogContent(r, paramsWithToken, getSO);
}
log(r.json().items, traceCalls, enduser);
return r
});
}
Loading
Loading