Skip to content

Commit

Permalink
test: add more performance tests (#1373)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the Title above -->

## Description

Added more performance tests and some improvements on github workflow
for performance tests

## Related Issue(s)

- #1326

## Verification

- [x] **Your** code builds clean without any errors or warnings
- [x] Manual testing done (required)
- [ ] Relevant automated test added (if you find this hard, leave it and
we'll help out)

## Documentation

- [x] 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

- **New Features**
- Introduced performance testing scripts for end-user search and GraphQL
search functionalities.
- Added a tagging system for performance tests with a new required input
parameter.
- Enhanced dialog creation and removal performance tests with improved
data handling.
- Implemented a new function for generating default thresholds for
performance tests.
- Added new performance testing scenarios for creating dialogs and
executing searches.

- **Bug Fixes**
- Updated performance test configurations to ensure correct environment
settings.

- **Refactor**
- Reorganized performance test scripts to utilize newly created utility
functions for better maintainability.
- Removed outdated performance testing scripts to streamline the testing
framework.

- **Documentation**
- Updated workflow configurations for clarity and improved execution
context.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
Co-authored-by: Are Almaas <arealmaas@gmail.com>
  • Loading branch information
3 people authored Nov 6, 2024
1 parent 493d247 commit 70a63cd
Show file tree
Hide file tree
Showing 20 changed files with 682 additions and 112 deletions.
16 changes: 12 additions & 4 deletions .github/workflows/dispatch-k6-performance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ on:
environment:
description: 'Environment'
required: true
default: 'staging'
default: 'yt01'
type: choice
options:
- test
- staging
- performance
- yt01
tokens:
description: 'Tokens to generate; for create dialog, search, none, or both'
required: true
Expand All @@ -26,10 +26,15 @@ on:
- enterprise
- personal
- none
tag:
description: 'tag the performance test'
required: true
default: 'Performance test'
type: string
vus:
description: 'Number of VUS'
required: true
default: 10
default: 1
type: number
duration:
description: 'Duration of test, ie 30s, 1m, 10m'
Expand All @@ -43,8 +48,11 @@ on:
type: choice
options:
- 'tests/k6/tests/serviceowner/performance/create-dialog.js'
- 'tests/k6/tests/enduser/performance/simple-search.js'
- 'tests/k6/tests/serviceowner/performance/create-remove-dialog.js'
- 'tests/k6/tests/enduser/performance/enduser-search.js'
- 'tests/k6/tests/graphql/performance/graphql-search.js'

run-name: ${{ inputs.tag }} vus ${{ inputs.vus }} duration ${{ inputs.duration }}
jobs:
k6-performance:
name: "Run K6 performance test"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/workflow-run-k6-performance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ on:
jobs:
k6-test:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
permissions:
checks: write
pull-requests: write
Expand Down
49 changes: 35 additions & 14 deletions tests/k6/common/config.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
const localBaseUrl = "https://localhost:7214/";
const localDockerBaseUrl = "https://host.docker.internal:7214/";
const testBaseUrl = "https://altinn-dev-api.azure-api.net/dialogporten/";
const yt01BaseUrl = "https://platform.yt01.altinn.cloud/dialogporten/";
const stagingBaseUrl = "https://platform.tt02.altinn.no/dialogporten/";
const prodBaseUrl = "https://platform.altinn.no/dialogporten/";

const endUserPath = "api/v1/enduser/";
const serviceOwnerPath = "api/v1/serviceowner/";
const graphqlPath = "graphql";

export const baseUrls = {
v1: {
enduser: {
localdev: "https://localhost:7214/api/v1/enduser/",
localdev_docker: "https://host.docker.internal:7214/api/v1/enduser/",
test: "https://altinn-dev-api.azure-api.net/dialogporten/api/v1/enduser/",
yt01: "https://platform.yt01.altinn.cloud/dialogporten/api/v1/enduser/",
staging: "https://platform.tt02.altinn.no/dialogporten/api/v1/enduser/",
prod: "https://platform.altinn.no/dialogporten/api/v1/enduser/"
localdev: localBaseUrl + endUserPath,
localdev_docker: localDockerBaseUrl + endUserPath,
test: testBaseUrl + endUserPath,
yt01: yt01BaseUrl + endUserPath,
staging: stagingBaseUrl + endUserPath,
prod: prodBaseUrl + endUserPath
},
serviceowner: {
localdev: "https://localhost:7214/api/v1/serviceowner/",
localdev_docker: "https://host.docker.internal:7214/api/v1/serviceowner/",
test: "https://altinn-dev-api.azure-api.net/dialogporten/api/v1/serviceowner/",
yt01: "https://platform.yt01.altinn.cloud/dialogporten/api/v1/serviceowner/",
staging: "https://platform.tt02.altinn.no/dialogporten/api/v1/serviceowner/",
prod: "https://platform.altinn.no/dialogporten/api/v1/serviceowner/"
}
}
localdev: localBaseUrl + serviceOwnerPath,
localdev_docker: localDockerBaseUrl + serviceOwnerPath,
test: testBaseUrl + serviceOwnerPath,
yt01: yt01BaseUrl + serviceOwnerPath,
staging: stagingBaseUrl + serviceOwnerPath,
prod: prodBaseUrl + serviceOwnerPath
},
graphql: {
localdev: localBaseUrl + graphqlPath,
localdev_docker: localDockerBaseUrl + graphqlPath,
test: testBaseUrl + graphqlPath,
yt01: yt01BaseUrl + graphqlPath,
staging: stagingBaseUrl + graphqlPath,
prod: prodBaseUrl + graphqlPath
},
}
};

export const defaultEndUserOrgNo = "310923044"; // ÆRLIG UROKKELIG TIGER AS
Expand All @@ -43,4 +62,6 @@ export const baseUrlEndUser = baseUrls[__ENV.API_VERSION]["enduser"][__ENV.API_E
export const baseUrlServiceOwner = baseUrls[__ENV.API_VERSION]["serviceowner"][__ENV.API_ENVIRONMENT];
export const tokenGeneratorEnv = __ENV.API_ENVIRONMENT == "yt01" ? "yt01" : "tt02"; // yt01 is the only environment that has a separate token generator environment

export const baseUrlGraphql = baseUrls[__ENV.API_VERSION]["graphql"][__ENV.API_ENVIRONMENT];

export const sentinelValue = "dialogporten-e2e-sentinel";
8 changes: 7 additions & 1 deletion tests/k6/common/request.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { default as http } from 'k6/http';
import { baseUrlEndUser, baseUrlServiceOwner } from './config.js'
import { baseUrlEndUser, baseUrlGraphql, baseUrlServiceOwner } from './config.js'
import { getServiceOwnerTokenFromGenerator, getEnduserTokenFromGenerator } from './token.js'
import { extend } from './extend.js'

Expand Down Expand Up @@ -125,3 +125,9 @@ export function patchEU(url, body, params = null, tokenOptions = null) {
export function deleteEU(url, params = null, tokenOptions = null) {
return http.request('DELETE', baseUrlEndUser + url, getEnduserRequestParams(params, tokenOptions));
}

export function postGQ(body, params = null) {
body = JSON.stringify({ query: body })
params = extend(true, {}, params, { headers: { 'Content-Type': 'application/json' }});
return http.post(baseUrlGraphql, body, params);
}
3 changes: 2 additions & 1 deletion tests/k6/common/testimports.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export {
putSO,
patchSO,
deleteSO,
purgeSO
purgeSO,
postGQ
} from './request.js';
export {
setTitle,
Expand Down
27 changes: 27 additions & 0 deletions tests/k6/tests/enduser/performance/enduser-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { enduserSearch } from '../../performancetest_common/simpleSearch.js'
import { getDefaultThresholds } from '../../performancetest_common/getDefaultThresholds.js';
import { endUsersWithTokens } from '../../performancetest_common/readTestdata.js';

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'],['enduser search',
'get dialog',
'get dialog activities',
'get dialog activity',
'get seenlogs',
'get seenlog',
'get transmissions',
'get transmission',
'get labellog'
])
};

export default function() {
if ((options.vus === undefined || options.vus === 1) && (options.iterations === undefined || options.iterations === 1)) {
enduserSearch(endUsersWithTokens[0]);
}
else {
enduserSearch(randomItem(endUsersWithTokens));
}
}

57 changes: 0 additions & 57 deletions tests/k6/tests/enduser/performance/simple-search.js

This file was deleted.

37 changes: 37 additions & 0 deletions tests/k6/tests/graphql/performance/graphql-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* The performance test for GraphQL search.
* 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 { 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.
*
* @property {string[]} summaryTrendStats - The summary trend statistics to include in the test results.
* @property {object} thresholds - The thresholds for the test metrics.
*/
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'],['graphql search'])
};

/**
* The default function for the performance test for GraphQL search.
*/
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)) {
graphqlSearch(endUsers[0]);
}
else {
graphqlSearch(randomItem(endUsers));
}
}


61 changes: 61 additions & 0 deletions tests/k6/tests/performancetest_common/createDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Common functions for creating dialogs.
*/
import { uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
import { describe } from "../../common/describe.js";
import { postSO, purgeSO } from "../../common/request.js";
import { expect } from "../../common/testimports.js";
import dialogToInsert from "../performancetest_data/01-create-dialog.js";

/**
* Creates a dialog.
*
* @param {Object} serviceOwner - The service owner object.
* @param {Object} endUser - The end user object.
*/
export function createDialog(serviceOwner, endUser) {
var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token,
traceparent: uuidv4()
},
tags: { name: 'create dialog' }
};

describe('create dialog', () => {
let r = postSO('dialogs', dialogToInsert(endUser.ssn, endUser.resource), paramsWithToken);
expect(r.status, 'response status').to.equal(201);
});

}

/**
* Creates a dialog and removes it.
*
* @param {Object} serviceOwner - The service owner object.
* @param {Object} endUser - The end user object.
*/
export function createAndRemoveDialog(serviceOwner, endUser) {
var paramsWithToken = {
headers: {
Authorization: "Bearer " + serviceOwner.token
},
tags: { name: 'create dialog' }
}

let dialogId = 0;
describe('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();
});

describe('remove dialog', () => {
paramsWithToken.tags.name = 'remove dialog';
if (dialogId) {
let r = purgeSO('dialogs/' + dialogId, paramsWithToken);
expect(r.status, 'response status').to.equal(204);
}
});
}
21 changes: 21 additions & 0 deletions tests/k6/tests/performancetest_common/getDefaultThresholds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Creates default thresholds configuration for K6 tests.
* @param {string[]} counters - Array of counter names
* @param {string[]} labels - Array of label names
* @returns {Object} Threshold configuration object
* @throws {Error} If inputs are invalid
*/
export function getDefaultThresholds(counters, labels) {
if (!Array.isArray(counters) || !Array.isArray(labels)) {
throw new Error('Both counters and labels must be arrays');
}
let thresholds = {
http_req_failed: ['rate<0.01']
};
for (const counter of counters) {
for (const label of labels) {
thresholds[`${counter}{name:${label}}`] = [];
}
}
return thresholds;
}
Loading

0 comments on commit 70a63cd

Please sign in to comment.