commit
24f045b3ab
5 changed files with 1587 additions and 0 deletions
@ -0,0 +1,57 @@ |
|||
# K6 scripts to run load tests against Keycloak |
|||
|
|||
## Setup |
|||
|
|||
```sh |
|||
sudo wget https://bintray.com/loadimpact/rpm/rpm -O /etc/yum.repos.d/bintray-loadimpact-rpm.repo |
|||
sudo yum install -y k6 |
|||
``` |
|||
|
|||
**/tmp/statsd_exporter.yaml**: |
|||
|
|||
```yaml |
|||
defaults: |
|||
observer_type: histogram |
|||
mappings: |
|||
- match: "k6.*" |
|||
name: "k6_${1}" |
|||
- match: "k6.check.*.*.*" |
|||
name: "k6_check" |
|||
labels: |
|||
http_name: "$1" |
|||
check_name: "$2" |
|||
outcome: "$3" |
|||
``` |
|||
|
|||
```sh |
|||
sudo podman run -d --name statsd_exporter -p 9102:9102 -p 8125:8125/udp -v /tmp/statsd_exporter.yaml:/etc/statsd_exporter.yaml quay.io/prometheus/statsd-exporter:latest --statsd.listen-udp=:8125 --statsd.mapping-config=/etc/statsd_exporter.yaml |
|||
``` |
|||
|
|||
**/tmp/prometheus.yaml**: |
|||
|
|||
```yaml |
|||
global: |
|||
scrape_interval: 1s |
|||
evaluation_interval: 1s |
|||
|
|||
scrape_configs: |
|||
- job_name: 'statsd_exporter' |
|||
static_configs: |
|||
- targets: ['statsd_exporter.dns.podman:9102'] |
|||
labels: {} |
|||
metric_relabel_configs: |
|||
- regex: '(job|instance)' |
|||
action: labeldrop |
|||
``` |
|||
|
|||
```sh |
|||
sudo podman run -d --name prometheus -p 9090:9090 -v /tmp/prometheus.yaml:/etc/prometheus/prometheus.yml prom/prometheus |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
```sh |
|||
export K6_DATADOG_TAG_BLACKLIST="url" |
|||
k6 run -o datadog login.js |
|||
``` |
|||
|
|||
@ -0,0 +1 @@ |
|||
* |
|||
File diff suppressed because it is too large
@ -0,0 +1,53 @@ |
|||
import { Rate } from "k6/metrics"; |
|||
|
|||
export function pickRealm(realmCount) { |
|||
var realmId = __VU % realmCount; |
|||
realmId = `${realmId}`.padStart(3, "0"); |
|||
var fileName = `data/realm-${realmId}.json`; |
|||
return JSON.parse(open(fileName)); |
|||
} |
|||
|
|||
export function pickClient(realm) { |
|||
var clients = realm.clients; |
|||
if (clients == null || clients.length == 0) { |
|||
return null; |
|||
} |
|||
|
|||
var i = Math.floor(Math.random() * Math.floor(clients.length)); |
|||
return clients[i]; |
|||
} |
|||
|
|||
export function pickUser(realm) { |
|||
var users = realm.users; |
|||
if (users == null || users.length == 0) { |
|||
return null; |
|||
} |
|||
|
|||
var i = Math.floor(Math.random() * Math.floor(users.length)); |
|||
return users[i]; |
|||
} |
|||
|
|||
export var script_errors = Rate("script_errors"); |
|||
export function wrapWithErrorCounting(fn) { |
|||
return () => { |
|||
try { |
|||
fn(); |
|||
script_errors.add(0); |
|||
} catch (e) { |
|||
script_errors.add(1); |
|||
throw e; |
|||
} |
|||
} |
|||
} |
|||
|
|||
export function buildQueryString(data) { |
|||
const result = []; |
|||
|
|||
Object.keys(data) |
|||
.forEach((key) => { |
|||
const encode = encodeURIComponent; |
|||
result.push(encode(key) + "=" + encode(data[key])); |
|||
}); |
|||
|
|||
return result.join("&"); |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
import http from 'k6/http'; |
|||
import { check, group, sleep } from 'k6'; |
|||
import { uuidv4 } from "https://jslib.k6.io/k6-utils/1.0.0/index.js"; |
|||
import { pickRealm, pickClient, pickUser, wrapWithErrorCounting, buildQueryString } from "./lib/keycloak.js"; |
|||
import { randomSeed } from 'k6'; |
|||
|
|||
export let options = { |
|||
stages: [ |
|||
{ duration: "20s", target: 5 }, |
|||
{ duration: "1m", target: 100 } |
|||
], |
|||
noVUConnectionReuse: true, |
|||
}; |
|||
|
|||
const realmCount = 10; |
|||
const realm = pickRealm(realmCount); |
|||
const realmId = realm.id; |
|||
|
|||
randomSeed(__VU); |
|||
|
|||
const BASE_URL = `http://hp-microserver.itix.fr/auth/realms/${realmId}`; |
|||
const LOGIN_ENDPOINT = `${BASE_URL}/protocol/openid-connect/auth`; |
|||
const TOKEN_ENDPOINT = `${BASE_URL}/protocol/openid-connect/token`; |
|||
const UI_HEADERS = { |
|||
"Accept": "text/html,application/xhtml+xml,application/xml", |
|||
"Accept-Encoding": "gzip, deflate", |
|||
"Accept-Language": "en-US,en;q=0.5", |
|||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0", |
|||
}; |
|||
|
|||
const LOGIN_PARAMS = { |
|||
"login": "true", |
|||
"response_type": "code", |
|||
}; |
|||
|
|||
function testKCLogin() { |
|||
var user = pickUser(realm); |
|||
var client = pickClient(realm); |
|||
|
|||
group('login', () => { |
|||
let login_params = Object.assign(LOGIN_PARAMS, { "client_id": client.clientId, "state": uuidv4(), "redirect_uri": client.redirectUris[0] }); |
|||
let query_string = buildQueryString(login_params); |
|||
let login_page = http.get(`${LOGIN_ENDPOINT}?${query_string}`, { "headers": UI_HEADERS, "tags": { name: "get-login-page" } }); |
|||
check(login_page, { |
|||
'login_page.status == 200': (http) => http.status === 200, |
|||
}); |
|||
|
|||
if (login_page == null || login_page.status !== 200) { |
|||
return; |
|||
} |
|||
|
|||
let authorization_response = login_page.submitForm({ |
|||
formSelector: '#kc-form-login', |
|||
fields: { username: user.username, password: user.credentials[0].value }, |
|||
params: { redirects: 0, "tags": { name: "authorization-request" } }, |
|||
}); |
|||
|
|||
check(authorization_response, { |
|||
'authorization_response.status == 302': (http) => http.status === 302, |
|||
}); |
|||
|
|||
let location = authorization_response.headers["Location"]; |
|||
let re = /[&?]code=([^&]+)(&|$)/; |
|||
let matches = [... location.matchAll(re) ]; |
|||
let code = matches[0][1]; |
|||
|
|||
let access_token_request = { |
|||
"grant_type": "authorization_code", |
|||
"code": code, |
|||
"redirect_uri": client.redirectUris[0], |
|||
"client_id": client.clientId, |
|||
"client_secret": client.secret |
|||
}; |
|||
let access_token_response = http.post(`${TOKEN_ENDPOINT}`, access_token_request, { "tags": { name: "access-token-request" } }); |
|||
|
|||
check(access_token_response, { |
|||
'access_token_response.status == 200': (http) => http.status === 200, |
|||
}); |
|||
}); |
|||
|
|||
sleep(2); |
|||
} |
|||
|
|||
export default wrapWithErrorCounting(testKCLogin); |
|||
|
|||
Loading…
Reference in new issue