Rungutan Documentation¶
Rungutan is a full 360° API Performance Testing SaaS platform, 100% Serverless.
As an evolved creature, Rungutan has extensive Load-Testing abilities, gained by experience, in order to survive in a fast-paced environment. Load Testing is its first language, so you will get along very well.
Useful links:
Design workflow oriented strategies¶
With sophisticated yet witty tools, a Rungutan is always prepared for what nature brings. Learning from this behaviour, our platform helps you simulate workflows to emulate user experience.
User’s nature will never surprise you again!
Schedule cron jobs to run against your platform regularly, for all-time awareness¶
These creatures always have each other’s back. They’ve developed multiple exercises in order to always be prepared in case of trouble.
You can now do the same!
Reach up to 100.000 requests/second in 15 concurrent regions¶
This species is more evolved than any other primates. It’s the first one who can actually Run. Why so?
Because due to its flexibility and simple design, can reach up to 100.000 requests/second.
Sample workflows¶
Here’s some sample workflows to show you the power of Rungutan:
LANDING PAGE¶
{
"test_name": "Blog post test",
"num_clients": 10,
"threads_per_region": 1,
"test_region": [ "us-east-1" ],
"workflow": [
{
"path": "https://example.com/",
"method": "GET"
},
{
"path": "https://example.com/blog",
"method": "GET"
},
{
"path": "https://example.com/blog/post-1",
"method": "GET"
},
]
}
BASIC AUTH¶
{
"test_name": "Blog post behind nginx HTTP access basic auth",
"run_time": 60,
"num_clients": 10,
"threads_per_region": 1,
"test_region": [ "us-east-1" ],
"workflow": [
{
"path": "https://example.com/",
"method": "GET",
"headers": {
"Authorization": "Basic some-token-here"
}
},
{
"path": "https://example.com/blog",
"method": "GET",
"headers": {
"Authorization": "Basic some-token-here"
}
},
{
"path": "https://example.com/blog/post-1",
"method": "GET",
"headers": {
"Authorization": "Basic some-token-here"
}
},
]
}
JSON RESPONSE WITH PATH EXPRESSION¶
{
"run_time": 60,
"num_clients": 10,
"threads_per_region": 1,
"workflow": [
{
"path": "https://example.com/v1/api/tests/list",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"X-Api-Key": "${vault.api_key}"
},
"extract": [
{
"parameter_name": "test_id",
"location": "body",
"json_path_expression": "Tests[*].test_id"
}
],
"data": "{\"team_id\":\"rungutan\"}",
"files": []
},
{
"path": "https://example.com/v1/api/tests/get",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"X-Api-Key": "${vault.api_key}"
},
"data": "{\"team_id\":\"rungutan\", \"test_id\":\"${test_id}\"}",
"extract": [],
"files": []
}
],
"test_region": [
"eu-west-1",
"eu-west-2"
],
"test_name": "List all tests, extract a random test_id using path expression and fetches its details"
}
First workflow step:
Hit the /v1/api/tests/list path with POST
Inject the X-Api-Key header with the relevant Vault key
Extract a random “test_id” key from the “Tests” array in the JSON response and STORE it in the variable named “test_id”
Second workflow step:
Hit the /v1/api/tests/get path with POST
Inject the X-Api-Key header with the relevant Vault key
Set the payload as “{“team_id”:”rungutan”, “test_id”:”${test_id}”}” by referencing the value of the variable that we extracted in the previous step
BASIC AUTH WITH FILE UPLOAD¶
{
"test_name": "Upload file to site with basic auth",
"run_time": 60,
"num_clients": 10,
"threads_per_region": 1,
"test_region": [ "us-east-1" ],
"workflow": [
{
"path": "https://example.com/",
"method": "GET",
"files": [
"file1", "file2"
]
"headers": {
"Authorization": "Basic some-token-here"
}
},
{
"path": "https://example.com/blog",
"method": "GET",
"headers": {
"Authorization": "Basic some-token-here"
}
},
{
"path": "https://example.com/blog/post-1",
"method": "GET",
"files": [
"file3"
]
"headers": {
"Authorization": "Basic some-token-here"
}
},
]
}
JWT LOGIN PLATFORM¶
{
"test_name": "Platform with JWT based auth",
"run_time": 60,
"num_clients": 10,
"threads_per_region": 1,
"test_region": [ "us-east-1" ],
"workflow": [
{
"path": "https://example.com/login",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"data": "user=${vault.username}&password=${vault.password}",
"extract": [
{
"parameter_name": "authtoken",
"location": "body",
"key": "access_token",
"default_value": ""
}
]
},
{
"path": "https://example.com/results",
"method": "POST",
"data": "{\"result_id\": \"1\"}"
"headers": {
"Authorization": "Bearer ${authtoken}"
}
}
]
}
First workflow step:
Hit the /login path with POST
Inject the username and password values from the relevant Vault keys into the payload
Extract the “access_token” key from the JSON response and STORE it in the variable named “authtoken”
Second workflow step:
Hit the /results path witht POST
Include a payload in the request
Set the header as “Bearer ${authtoken}” by referencing the value of the variable that we extracted in the previous step
LOGIN E-COMMERCE, PUSH COOKIES AND UPDATE SHIPPING ADDRESS¶
{
"run_time": 60,
"num_clients": 10,
"threads_per_region": 1,
"workflow": [
{
"path": "https://example.com/login",
"method": "GET",
"files": [],
"data": "",
"headers": {
"authority": "${vault.domain_name}",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "macOS",
"upgrade-insecure-requests": "1",
"dnt": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"referer": "https://${vault.domain_name}/"
},
"extract": [
{
"parameter_name": "csrftoken",
"location": "body",
"element_with_regex": "type=\"hidden\" name=\"ci_csrf_token\" value=\"(.+?)\""
}
],
"extract_cookies": "yes"
},
{
"path": "https://example.com/login",
"method": "POST",
"files": [],
"data": "ci_csrf_token=${csrftoken}&login-email=${vault.login_email}&login-password=${vault.login_password}&form-login-submit=1",
"headers": {
"authority": "${vault.domain_name}",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "macOS",
"upgrade-insecure-requests": "1",
"dnt": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"referer": "https://${vault.domain_name}/login",
"origin": "https://${vault.domain_name}",
"content-type": "application/x-www-form-urlencoded"
},
"extract": [],
"extract_cookies": "no"
},
{
"path": "https://example.com/dashboard/address_book/shipping",
"method": "GET",
"files": [],
"data": "",
"headers": {
"authority": "${vault.domain_name}",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "macOS",
"upgrade-insecure-requests": "1",
"dnt": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"referer": "https://${vault.domain_name}/dashboard",
"origin": "https://${vault.domain_name}"
},
"extract": [
{
"parameter_name": "shipping_address_id",
"location": "body",
"element_with_regex": "/dashboard/address_book/edit_shipping/(.+?)"
}
],
"extract_cookies": "no"
},
{
"path": "https://example.com/dashboard/address_book/edit_shipping/${shipping_address_id}/ajax-save-address",
"method": "POST",
"files": [],
"data": "action=ajax_save_address&validate_data=ci_csrf_token%3D${csrftoken}%26address_book_id%3D${shipping_address_id}%26zipcode%3D${vault.zip_code}&address_book_id=${shipping_address_id}&ci_csrf_token=${csrftoken}",
"headers": {
"authority": "${vault.domain_name}",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "macOS",
"upgrade-insecure-requests": "1",
"dnt": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
"accept": "*/*",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "cors",
"sec-fetch-user": "?1",
"sec-fetch-dest": "empty",
"referer": "https://${vault.domain_name}/dashboard/address_book/edit_shipping/${shipping_address_id}",
"origin": "https://${vault.domain_name}",
"x-requested-with": "XMLHttpRequest",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
"extract": [],
"extract_cookies": "no"
},
{
"path": "https://example.com/logout",
"method": "POST",
"files": [],
"data": "",
"headers": {
"authority": "${vault.domain_name}",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "macOS",
"upgrade-insecure-requests": "1",
"dnt": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"sec-fetch-site": "same-origin",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"referer": "https://${vault.domain_name}/dashboard/address_book/shipping",
"origin": "https://${vault.domain_name}"
},
"extract": [],
"extract_cookies": "no"
}
],
"test_region": [
"eu-central-1"
],
"test_name": "Login GET + Login POST + View shipping addresses GET + Update address with ajax POST + Logout GET"
}
First workflow step:
Hit the login URL with the METHOD GET
EXTRACT the CSRF token value by scanning the page for the actual value of csrf-token and STORE IT with variable name csrftoken
Second workflow step:
Use the value of the PREVIOUSLY STORED variable csrftoken and construct the LOGIN credentials by fetching the username and password from vault
Hit that URL with the METHOD POST
EXTRACT COOKIES and push them towards future workflow steps
Third workflow step:
Access the Shipping page
EXTRACT the ID of the shipping address stored in database and STORE IT with variable name shipping_address_id
Forth workflow step: * Update the shipping address by simulating an AJAX post call with sec-fetch-mode header as CORS and XMLHttpRequest as the “x-requested-with” header
Fifth workflow step
Simply log out the user
CSV UPDATE USER DETAILS¶
{
"test_name": "Update email + phone number - 1000 users csv",
"run_time": 60,
"num_clients": 10,
"threads_per_region": 5,
"workflow": [
{
"path": "https://example.com/user/${csv.testprod.3}/profile",
"method": "GET",
"data": "",
"headers": {
"Content-Type": "application/json",
"Authorization": "${vault.api_key}"
},
"extract": [
{
"parameter_name": "profile_id",
"location": "body",
"key": "profile_id_extracted"
}
]
},
{
"path": "https://example.com/user/${profile_id_extracted}/profile-details",
"method": "POST",
"data": "{\"phone_number\": \"+14041234567\"}",
"headers": {
"Content-Type": "application/json",
"Authorization": "${vault.api_key}"
}
},
{
"path": "https://example.com/user/${profile_id_extracted}/profile-details",
"method": "POST",
"data": "{\"email\": \"[email protected]"}",
"headers": {
"Content-Type": "application/json",
"Authorization": "${vault.api_key}"
}
}
],
"test_region": [
"us-east-1",
"us-east-2"
]
}
Here’s the step by step long explanation:
First workflow step:
Extract a random ROW from file testprod
From that ROW, get the value of the COLUMN with index 3
With that value, construct the URL -> /user/${csv.testprod.3}/profile
Hit that URL with the METHOD GET
Authenticate the API request using a VAULT key with the name api_key by placing it in the header key called “Authorization”
EXTRACT the parameter profile_id from the received JSON response and STORE IT with variable name profile_id_extracted
Second workflow step:
Use the value of the PREVIOUSLY STORED variable profile_id_extracted and construct the URL -> /user/${profile_id_extracted}/profile-details
Hit that URL with the METHOD POST
Authenticate the API request using a VAULT key with the name api_key by placing it in the header key called “Authorization”
Push the appropriate PAYLOAD using the json-escaped data field in order to update the phone number
Third workflow step:
Use the SAME value of the PREVIOUSLY STORED variable profile_id_extracted and construct the URL -> /user/${profile_id_extracted}/profile-details
Hit that URL with the METHOD POST
Authenticate the API request using a VAULT key with the name api_key by placing it in the header key called “Authorization”
Push the appropriate PAYLOAD using the json-escaped data field in order to update the email address
- Fun facts
- Concurrent regions list
- Overall mode
- Threads per region logic
- Simulate 5 million requests per minute
- JSON payload
- Extract nested json response
- Extract nested json response with array
- Extract specific key with json path expression from response body
- Extract random key from collection of items with json path expression from response body
- Extract using regex
- Sharing secret stuff
- Why blank steps :(
- Sample workflows
- Teams
- API Keys
- Dashboard
- Alerts
- Vault
- File System
- CSV
- Tests
- Templates
- Cron jobs
- Integrations
- Results
- Team members
- Profile
- Billing