From 9d9d71eb56af0b9ba26d59a88045fe269698ffc5 Mon Sep 17 00:00:00 2001 From: Simon Kirillov Date: Mon, 25 Dec 2023 13:35:16 +0100 Subject: [PATCH] Add k6 testing script (#62) * Fix .gitignore * Fix httpbin.json OpenAPI manifest * Add k6 script --- .gitignore | 2 +- resources/dev/httpbin.json | 391 ++++++----- resources/dev/k6-test/script.js | 1130 +++++++++++++++++++++++++++++++ 3 files changed, 1354 insertions(+), 169 deletions(-) create mode 100644 resources/dev/k6-test/script.js diff --git a/.gitignore b/.gitignore index cbc4afa..27028b9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,4 @@ vendor/ .DS_Store .idea/ -dev/ +/dev/ diff --git a/resources/dev/httpbin.json b/resources/dev/httpbin.json index bbe252d..8cec060 100644 --- a/resources/dev/httpbin.json +++ b/resources/dev/httpbin.json @@ -72,7 +72,10 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 5 } ], "responses": { @@ -154,7 +157,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "anything" } ], "tags": [ @@ -176,7 +180,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "anything" } ], "tags": [ @@ -198,7 +203,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "anything" } ], "tags": [ @@ -220,7 +226,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "anything" } ], "tags": [ @@ -242,7 +249,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "anything" } ], "tags": [ @@ -269,9 +277,9 @@ "in": "path", "required": true, "schema": { - "type": "string", - "default": "SFRUUEJJTiBpcyBhd2Vzb21l" - } + "type": "string" + }, + "example": "SFRUUEJJTiBpcyBhd2Vzb21l" } ], "responses": { @@ -295,7 +303,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "user" }, { "name": "passwd", @@ -303,12 +312,13 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "password" } ], "responses": { "200": { - "description": "Sucessful authentication.", + "description": "Successful authentication.", "content": {} }, "401": { @@ -328,12 +338,15 @@ { "name": "Authorization", "in": "header", - "schema": {} + "schema": { + "type": "string" + }, + "example": "Bearer test-token" } ], "responses": { "200": { - "description": "Sucessful authentication.", + "description": "Successful authentication.", "content": {} }, "401": { @@ -368,7 +381,10 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 128 } ], "responses": { @@ -389,12 +405,18 @@ { "name": "If-Modified-Since", "in": "header", - "schema": {} + "schema": { + "type": "string" + }, + "example": "Mon,21 Aug 2023 07:47:54 GMT" }, { "name": "If-None-Match", "in": "header", - "schema": {} + "schema": { + "type": "string" + }, + "example": "01ab392a8f434b40880c5581b2db66bb" } ], "responses": { @@ -422,7 +444,8 @@ "required": true, "schema": { "type": "integer" - } + }, + "example": 3600 } ], "responses": { @@ -458,7 +481,15 @@ "name": "freeform", "in": "query", "allowEmptyValue": true, - "schema": {} + "style": "form", + "explode": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "example": "{ \"cookie1\": \"value1\", \"cookie2\": \"value2\" }" } ], "responses": { @@ -480,7 +511,15 @@ "name": "freeform", "in": "query", "allowEmptyValue": true, - "schema": {} + "style": "form", + "explode": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "example": "{ \"cookie1\": \"value1\", \"cookie2\": \"value2\" }" } ], "responses": { @@ -504,7 +543,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "cookie1" }, { "name": "value", @@ -512,7 +552,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "value1" } ], "responses": { @@ -531,7 +572,7 @@ "summary": "Returns Deflate-encoded data.", "responses": { "200": { - "description": "Defalte-encoded data.", + "description": "Deflate-encoded data.", "content": {} } } @@ -548,7 +589,10 @@ "name": "delay", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 3 } ], "responses": { @@ -568,7 +612,10 @@ "name": "delay", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 3 } ], "responses": { @@ -588,7 +635,10 @@ "name": "delay", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 3 } ], "responses": { @@ -608,7 +658,10 @@ "name": "delay", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 3 } ], "responses": { @@ -628,7 +681,10 @@ "name": "delay", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 3 } ], "responses": { @@ -681,7 +737,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "auth" }, { "name": "user", @@ -689,7 +746,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "user" }, { "name": "passwd", @@ -697,12 +755,13 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "password" } ], "responses": { "200": { - "description": "Sucessful authentication.", + "description": "Successful authentication.", "content": {} }, "401": { @@ -726,7 +785,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "auth" }, { "name": "user", @@ -734,7 +794,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "user" }, { "name": "passwd", @@ -742,7 +803,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "password" }, { "name": "algorithm", @@ -750,14 +812,14 @@ "description": "MD5, SHA-256, SHA-512", "required": true, "schema": { - "type": "string", - "default": "MD5" - } + "type": "string" + }, + "example": "MD5" } ], "responses": { "200": { - "description": "Sucessful authentication.", + "description": "Successful authentication.", "content": {} }, "401": { @@ -782,7 +844,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "auth" }, { "name": "user", @@ -790,7 +853,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "user" }, { "name": "passwd", @@ -798,7 +862,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "password" }, { "name": "algorithm", @@ -806,23 +871,23 @@ "description": "MD5, SHA-256, SHA-512", "required": true, "schema": { - "type": "string", - "default": "MD5" - } + "type": "string" + }, + "example": "MD5" }, { "name": "stale_after", "in": "path", "required": true, "schema": { - "type": "string", - "default": "never" - } + "type": "string" + }, + "example": "never" } ], "responses": { "200": { - "description": "Sucessful authentication.", + "description": "Successful authentication.", "content": {} }, "401": { @@ -844,36 +909,36 @@ "in": "query", "description": "The amount of time (in seconds) over which to drip each byte", "schema": { - "type": "number", - "default": 2 - } + "type": "number" + }, + "example": 2 }, { "name": "numbytes", "in": "query", "description": "The number of bytes to respond with", "schema": { - "type": "integer", - "default": 10 - } + "type": "integer" + }, + "example": 10 }, { "name": "code", "in": "query", "description": "The response code that will be returned", "schema": { - "type": "integer", - "default": 200 - } + "type": "integer" + }, + "example": 200 }, { "name": "delay", "in": "query", "description": "The amount of time (in seconds) to delay before responding", "schema": { - "type": "number", - "default": 2 - } + "type": "number" + }, + "example": 2 } ], "responses": { @@ -911,17 +976,24 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "01ab392a8f434b40880c5581b2db66bb" }, { "name": "If-None-Match", "in": "header", - "schema": {} + "schema": { + "type": "string" + }, + "example": "" }, { "name": "If-Match", "in": "header", - "schema": {} + "schema": { + "type": "string" + }, + "example": "" } ], "responses": { @@ -991,7 +1063,8 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "user" }, { "name": "passwd", @@ -999,12 +1072,22 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "password" + }, + { + "name": "Authorization", + "in": "header", + "required": true, + "schema": { + "type": "string" + }, + "example": "Basic dXNlcjpwYXNzd29yZA==" } ], "responses": { "200": { - "description": "Sucessful authentication.", + "description": "Successful authentication.", "content": {} }, "404": { @@ -1137,13 +1220,19 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 5 }, { "name": "offset", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 0 } ], "responses": { @@ -1207,7 +1296,10 @@ "name": "numbytes", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 128 } ], "responses": { @@ -1231,98 +1323,18 @@ "required": true, "schema": { "type": "string" - } + }, + "example": "https://example.com/" }, { "name": "status_code", "in": "query", - "schema": {} - } - ], - "responses": { - "302": { - "description": "A redirection.", - "content": {} - } - } - }, - "put": { - "tags": [ - "Redirects" - ], - "summary": "302/3XX Redirects to the given URL.", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "required": [ - "url" - ], - "properties": { - "url": { - "type": "string" - }, - "status_code": {} - } - } - } - }, - "required": true - }, - "responses": { - "302": { - "description": "A redirection.", - "content": {} - } - } - }, - "post": { - "tags": [ - "Redirects" - ], - "summary": "302/3XX Redirects to the given URL.", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "required": [ - "url" - ], - "properties": { - "url": { - "type": "string" - }, - "status_code": {} - } - } - } - }, - "required": true - }, - "responses": { - "302": { - "description": "A redirection.", - "content": {} - } - } - }, - "delete": { - "tags": [ - "Redirects" - ], - "summary": "302/3XX Redirects to the given URL.", - "responses": { - "302": { - "description": "A redirection.", - "content": {} + "schema": { + "type": "integer" + }, + "example": 302 } - } - }, - "patch": { - "tags": [ - "Redirects" ], - "summary": "302/3XX Redirects to the given URL.", "responses": { "302": { "description": "A redirection.", @@ -1342,7 +1354,10 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 5 } ], "responses": { @@ -1364,7 +1379,10 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 5 } ], "responses": { @@ -1386,7 +1404,15 @@ "name": "freeform", "in": "query", "allowEmptyValue": true, - "schema": {} + "style": "form", + "explode": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "example": "{ \"X-Header1\": \"value1\", \"X-Header2\": \"value2\" }" } ], "responses": { @@ -1406,7 +1432,15 @@ "name": "freeform", "in": "query", "allowEmptyValue": true, - "schema": {} + "style": "form", + "explode": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "example": "{ \"cookie1\": \"value1\", \"cookie2\": \"value2\" }" } ], "responses": { @@ -1442,7 +1476,10 @@ "name": "codes", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 200 } ], "responses": { @@ -1478,7 +1515,10 @@ "name": "codes", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 200 } ], "responses": { @@ -1514,7 +1554,10 @@ "name": "codes", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 200 } ], "responses": { @@ -1550,7 +1593,10 @@ "name": "codes", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 200 } ], "responses": { @@ -1586,7 +1632,10 @@ "name": "codes", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 200 } ], "responses": { @@ -1624,7 +1673,10 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 128 } ], "responses": { @@ -1646,7 +1698,10 @@ "name": "n", "in": "path", "required": true, - "schema": {} + "schema": { + "type": "integer" + }, + "example": 5 } ], "responses": { @@ -1701,4 +1756,4 @@ } }, "components": {} -} \ No newline at end of file +} diff --git a/resources/dev/k6-test/script.js b/resources/dev/k6-test/script.js new file mode 100644 index 0000000..c39ca8d --- /dev/null +++ b/resources/dev/k6-test/script.js @@ -0,0 +1,1130 @@ +/* + * httpbin.org + * A simple HTTP Request & Response Service.

Run locally: $ docker run -p 80:80 kennethreitz/httpbin + * + * OpenAPI spec version: 0.9.2 + * Contact: me@kennethreitz.org + * + * NOTE: This class is auto generated by OpenAPI Generator. + * https://github.com/OpenAPITools/openapi-generator + * + * OpenAPI generator version: 7.0.0-SNAPSHOT + */ + + +import http from "k6/http"; +import { b64encode, b64decode } from "k6/encoding"; +import { group, check, sleep } from "k6"; +import { URL, URLSearchParams } from 'https://jslib.k6.io/url/1.0.0/index.js'; + +const BASE_URL = "http://host.docker.internal:8090"; +// Sleep duration between successive requests. +// You might want to edit the value of this variable or remove calls to the sleep function on the script. +const SLEEP_DURATION = 0.1; + +export default function() { + group("/post", () => { + + // Request No. 1: + { + let url = BASE_URL + `/post`; + let request = http.post(url); + + check(request, { + "The request's POST parameters.": (r) => r.status === 200 + }); + } + }); + + group("/range/{numbytes}", () => { + let numbytes = '128'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/range/${numbytes}`; + let params = {responseType: 'binary'} + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "Bytes.": (r) => r.body.byteLength === parseInt(numbytes), + }); + } + }); + + group("/hidden-basic-auth/{user}/{passwd}", () => { + let passwd = 'password'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let user = 'user'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + let authToken = b64encode(`${user}:${passwd}`); + let authHeader = `Basic ${authToken}`; + + // Request No. 1: + { + let url = BASE_URL + `/hidden-basic-auth/${user}/${passwd}`; + let params = {headers: {"Authorization": `${authHeader}`}}; + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "is authenticated": (r) => r.json().authenticated === true, + "is correct user": (r) => r.json().user === user, + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/hidden-basic-auth/${user}/${passwd}`; + let request = http.get(url); + + check(request, { + "Unsuccessful authentication.": (r) => r.status === 404 + }); + } + }); + + group("/base64/{value}", () => { + let value = 'SFRUUEJJTiBpcyBhd2Vzb21l'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let decodedValue = b64decode(value, 'std', 's'); + + // Request No. 1: + { + let url = BASE_URL + `/base64/${value}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "Decoded base64 content.": (r) => r.body === decodedValue, + }); + } + }); + + group("/user-agent", () => { + + // Request No. 1: + { + let url = BASE_URL + `/user-agent`; + let request = http.get(url); + + check(request, { + "The request's User-Agent header.": (r) => r.status === 200 + }); + } + }); + + group("/etag/{etag}", () => { + let etag = '01ab392a8f434b40880c5581b2db66bb'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/etag/${etag}`; + let request = http.get(url); + + check(request, { + "Normal response": (r) => r.status === 200 + }); + } + }); + + group("/digest-auth/{qop}/{user}/{passwd}", () => { + let qop = 'auth'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let passwd = 'password'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let user = 'user'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let parsedURL = new URL(BASE_URL); + parsedURL.username = user; + parsedURL.password = passwd; + parsedURL.pathname = `/digest-auth/${qop}/${user}/${passwd}`; + + let url = parsedURL.toString(); + let params = {auth: "digest"}; + let request = http.get(url, params); + + // throw new Error(url) + + check(request, { + "status is 200": (r) => r.status === 200, + "is authenticated": (r) => r.json().authenticated === true, + "is correct user": (r) => r.json().user === user, + }); + } + }); + + group("/ip", () => { + + // Request No. 1: + { + let url = BASE_URL + `/ip`; + let request = http.get(url); + + check(request, { + "The Requester's IP Address.": (r) => r.status === 200 + }); + } + }); + + group("/put", () => { + + // Request No. 1: + { + let url = BASE_URL + `/put`; + let request = http.put(url); + + check(request, { + "The request's PUT parameters.": (r) => r.status === 200 + }); + } + }); + + group("/cookies", () => { + + // Request No. 1: + { + let url = BASE_URL + `/cookies`; + let request = http.get(url); + + check(request, { + "Set cookies.": (r) => r.status === 200 + }); + } + }); + + group("/brotli", () => { + + // Request No. 1: + { + let url = BASE_URL + `/brotli`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "Brotli-encoded data.": (r) => r.json().brotli === true, + }); + } + }); + + group("/status/{codes}", () => { + let codes = '200'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/status/${codes}`; + let request = http.get(url); + + check(request, { + "Success": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/status/${codes}`; + let request = http.put(url); + + check(request, { + "Success": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 3: + { + let url = BASE_URL + `/status/${codes}`; + let request = http.post(url); + + check(request, { + "Success": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 4: + { + let url = BASE_URL + `/status/${codes}`; + let request = http.del(url); + + check(request, { + "Success": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 5: + { + let url = BASE_URL + `/status/${codes}`; + let request = http.patch(url); + + check(request, { + "Success": (r) => r.status === 200 + }); + } + }); + + group("/html", () => { + + // Request No. 1: + { + let url = BASE_URL + `/html`; + let request = http.get(url); + + check(request, { + "An HTML page.": (r) => r.status === 200 + }); + } + }); + + group("/xml", () => { + + // Request No. 1: + { + let url = BASE_URL + `/xml`; + let request = http.get(url); + + check(request, { + "An XML document.": (r) => r.status === 200 + }); + } + }); + + group("/drip", () => { + let duration = '2'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let code = '200'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let delay = '2'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let numbytes = '10'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/drip?duration=${duration}&numbytes=${numbytes}&code=${code}&delay=${delay}`; + let params = {responseType: 'binary'} + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "A dripped response.": (r) => r.body.byteLength === parseInt(numbytes), + }); + } + }); + + group("/image", () => { + + // Request No. 1: + { + let url = BASE_URL + `/image`; + let request = http.get(url); + + check(request, { + "An image.": (r) => r.status === 200 + }); + } + }); + + group("/bytes/{n}", () => { + let n = '128'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/bytes/${n}`; + let params = {responseType: 'binary'} + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "Bytes.": (r) => r.body.byteLength === parseInt(n), + }); + } + }); + + group("/uuid", () => { + + // Request No. 1: + { + let url = BASE_URL + `/uuid`; + let request = http.get(url); + + check(request, { + "A UUID4.": (r) => r.status === 200 + }); + } + }); + + group("/relative-redirect/{n}", () => { + let n = '5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/relative-redirect/${n}`; + let next_url = `/relative-redirect/${parseInt(n) - 1}`; + let params = {redirects: 0}; + let request = http.get(url, params); + + check(request, { + "status is 302": (r) => r.status === 302, + "is next location correct": (r) => r.headers["Location"] === next_url, + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/relative-redirect/${n}`; + let resultUrl = BASE_URL + "/get"; + let request = http.get(url); + + check(request, { + "is status 200 after redirects": (r) => r.status === 200, + "is correct destination": (r) => r.url === resultUrl, + }); + } + }); + + group("/digest-auth/{qop}/{user}/{passwd}/{algorithm}/{stale_after}", () => { + let qop = 'auth'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let staleAfter = 'never'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let passwd = 'password'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let user = 'user'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let algorithm = 'MD5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let parsedURL = new URL(BASE_URL); + parsedURL.username = user; + parsedURL.password = passwd; + parsedURL.pathname = `/digest-auth/${qop}/${user}/${passwd}/${algorithm}/${staleAfter}`; + + let url = parsedURL.toString(); + let params = {auth: "digest"}; + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "is authenticated": (r) => r.json().authenticated === true, + "is correct user": (r) => r.json().user === user, + }); + } + }); + + group("/redirect/{n}", () => { + let n = '5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/redirect/${n}`; + let next_url = `/relative-redirect/${parseInt(n) - 1}`; + let params = {redirects: 0}; + let request = http.get(url, params); + + check(request, { + "status is 302": (r) => r.status === 302, + "is next location correct": (r) => r.headers["Location"] === next_url, + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/redirect/${n}`; + let resultUrl = BASE_URL + "/get"; + let request = http.get(url); + + check(request, { + "is status 200 after redirects": (r) => r.status === 200, + "is correct destination": (r) => r.url === resultUrl, + }); + } + }); + + group("/cookies/set", () => { + let freeform = '{ \"cookie1\": \"value1\", \"cookie2\": \"value2\" }'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let parsedJSON = JSON.parse(freeform); + let queryString = new URLSearchParams(parsedJSON).toString(); + + // Request No. 1: + { + let url = BASE_URL + `/cookies/set?${queryString}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "cookie1 is present": (r) => r.json()["cookies"]["cookie1"] === parsedJSON["cookie1"], + "cookie2 is present": (r) => r.json()["cookies"]["cookie2"] === parsedJSON["cookie2"], + }); + } + }); + + group("/cookies/delete", () => { + let freeform = '{ \"cookie1\": \"value1\", \"cookie2\": \"value2\" }'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let parsedJSON = JSON.parse(freeform); + let queryString = new URLSearchParams(parsedJSON).toString(); + + // Request No. 1: + { + let url = BASE_URL + `/cookies/delete?${queryString}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "cookie1 is gone": (r) => r.json()["cookies"]["cookie1"] === undefined, + "cookie2 is gone": (r) => r.json()["cookies"]["cookie2"] === undefined, + }); + } + }); + + group("/delete", () => { + + // Request No. 1: + { + let url = BASE_URL + `/delete`; + let request = http.del(url); + + check(request, { + "The request's DELETE parameters.": (r) => r.status === 200 + }); + } + }); + + group("/basic-auth/{user}/{passwd}", () => { + let passwd = 'password'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let user = 'user'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + let authToken = b64encode(`${user}:${passwd}`); + let authHeader = `Basic ${authToken}`; + + // Request No. 1: + { + let url = BASE_URL + `/basic-auth/${user}/${passwd}`; + let params = {headers: {"Authorization": `${authHeader}`}}; + let request = http.get(url, params); + + check(request, { + "Successful authentication.": (r) => r.status === 200, + "is authenticated": (r) => r.json().authenticated === true, + "is correct user": (r) => r.json().user === user, + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/basic-auth/${user}/${passwd}`; + let request = http.get(url); + + check(request, { + "Unsuccessful authentication.": (r) => r.status === 401 + }); + } + }); + + group("/image/png", () => { + + // Request No. 1: + { + let url = BASE_URL + `/image/png`; + let request = http.get(url); + + check(request, { + "A PNG image.": (r) => r.status === 200 + }); + } + }); + + group("/absolute-redirect/{n}", () => { + let n = '5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/absolute-redirect/${n}`; + let next_url = BASE_URL + `/absolute-redirect/${parseInt(n) - 1}`; + let params = {redirects: 0}; + let request = http.get(url, params); + + check(request, { + "status is 302": (r) => r.status === 302, + "is next location correct": (r) => r.headers["Location"] === next_url, + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/absolute-redirect/${n}`; + let resultUrl = BASE_URL + "/get"; + let request = http.get(url); + + check(request, { + "is status 200 after redirects": (r) => r.status === 200, + "is correct destination": (r) => r.url === resultUrl, + }); + } + }); + + group("/delay/{delay}", () => { + let delay = '3'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/delay/${delay}`; + let request = http.get(url); + + check(request, { + "A delayed response.": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/delay/${delay}`; + let request = http.put(url); + + check(request, { + "A delayed response.": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 3: + { + let url = BASE_URL + `/delay/${delay}`; + let request = http.post(url); + + check(request, { + "A delayed response.": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 4: + { + let url = BASE_URL + `/delay/${delay}`; + let request = http.del(url); + + check(request, { + "A delayed response.": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 5: + { + let url = BASE_URL + `/delay/${delay}`; + let request = http.patch(url); + + check(request, { + "A delayed response.": (r) => r.status === 200 + }); + } + }); + + group("/encoding/utf8", () => { + + // Request No. 1: + { + let url = BASE_URL + `/encoding/utf8`; + let request = http.get(url); + + check(request, { + "Encoded UTF-8 content.": (r) => r.status === 200 + }); + } + }); + + group("/response-headers", () => { + let freeform = '{ \"X-Header1\": \"value1\", \"X-Header2\": \"value2\" }'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let parsedJSON = JSON.parse(freeform); + let queryString = new URLSearchParams(parsedJSON).toString(); + + // Request No. 1: + { + let url = BASE_URL + `/response-headers?${queryString}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "X-Header1 is present": (r) => r.headers["X-Header1"] === parsedJSON["X-Header1"], + "X-Header2 is present": (r) => r.headers["X-Header2"] === parsedJSON["X-Header2"] + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/response-headers?${queryString}`; + let request = http.post(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "X-Header1 is present": (r) => r.headers["X-Header1"] === parsedJSON["X-Header1"], + "X-Header2 is present": (r) => r.headers["X-Header2"] === parsedJSON["X-Header2"] + }); + } + }); + + group("/headers", () => { + + // Request No. 1: + { + let url = BASE_URL + `/headers`; + let request = http.get(url); + + check(request, { + "The request's headers.": (r) => r.status === 200 + }); + } + }); + + group("/gzip", () => { + + // Request No. 1: + { + let url = BASE_URL + `/gzip`; + let request = http.get(url); + + check(request, { + "GZip-encoded data.": (r) => r.status === 200 + }); + } + }); + + group("/get", () => { + + // Request No. 1: + { + let url = BASE_URL + `/get`; + let request = http.get(url); + + check(request, { + "The request's query parameters.": (r) => r.status === 200 + }); + } + }); + + group("/links/{n}/{offset}", () => { + let offset = '0'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let n = '5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/links/${n}/${offset}`; + let request = http.get(url); + + check(request, { + "HTML links.": (r) => r.status === 200 + }); + } + }); + + group("/cache/{value}", () => { + let value = '3600'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/cache/${value}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "Cache control set": (r) => r.headers["Cache-Control"].includes(`max-age=${value}`), + }); + } + }); + + group("/image/jpeg", () => { + + // Request No. 1: + { + let url = BASE_URL + `/image/jpeg`; + let request = http.get(url); + + check(request, { + "A JPEG image.": (r) => r.status === 200 + }); + } + }); + + group("/json", () => { + + // Request No. 1: + { + let url = BASE_URL + `/json`; + let request = http.get(url); + + check(request, { + "An JSON document.": (r) => r.status === 200 + }); + } + }); + + group("/stream/{n}", () => { + let n = '5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/stream/${n}`; + let request = http.get(url); + + check(request, { + "Streamed JSON responses.": (r) => r.status === 200 + }); + } + }); + + group("/stream-bytes/{n}", () => { + let n = '128'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/stream-bytes/${n}`; + let params = {responseType: 'binary'} + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "Bytes.": (r) => r.body.byteLength === parseInt(n), + }); + } + }); + + group("/anything/{anything}", () => { + let anything = 'anything'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/anything/${anything}`; + let request = http.get(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/anything/${anything}`; + let request = http.put(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 3: + { + let url = BASE_URL + `/anything/${anything}`; + let request = http.post(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 4: + { + let url = BASE_URL + `/anything/${anything}`; + let request = http.del(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 5: + { + let url = BASE_URL + `/anything/${anything}`; + let request = http.patch(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + } + }); + + group("/cookies/set/{name}/{value}", () => { + let name = 'cookie1'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let value = 'value1'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/cookies/set/${name}/${value}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200, + "cookie1 is present": (r) => r.json()["cookies"][name] === value + }); + } + }); + + group("/image/webp", () => { + + // Request No. 1: + { + let url = BASE_URL + `/image/webp`; + let request = http.get(url); + + check(request, { + "A WEBP image.": (r) => r.status === 200 + }); + } + }); + + group("/cache", () => { + let ifModifiedSince = "Mon,21 Aug 2023 07:47:54 GMT"; + let ifNoneMatch = "01ab392a8f434b40880c5581b2db66bb"; + + // Request No. 1: + { + let url = BASE_URL + `/cache`; + let request = http.get(url); + + check(request, { + "Cached response": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/cache`; + let params = {headers: {"If-Modified-Since": `${ifModifiedSince}`}}; + let request = http.get(url, params); + + check(request, { + "Cached response": (r) => r.status === 304 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 3: + { + let url = BASE_URL + `/cache`; + let params = {headers: {"If-None-Match": `${ifNoneMatch}`}}; + let request = http.get(url, params); + + check(request, { + "Cached response": (r) => r.status === 304 + }); + } + }); + + group("/anything", () => { + + // Request No. 1: + { + let url = BASE_URL + `/anything`; + let request = http.get(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/anything`; + let request = http.put(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 3: + { + let url = BASE_URL + `/anything`; + let request = http.post(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 4: + { + let url = BASE_URL + `/anything`; + let request = http.del(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 5: + { + let url = BASE_URL + `/anything`; + let request = http.patch(url); + + check(request, { + "Anything passed in request": (r) => r.status === 200 + }); + } + }); + + group("/bearer", () => { + let authHeader = "Bearer test-token"; + + // Request No. 1: + { + let url = BASE_URL + `/bearer`; + let params = {headers: {"Authorization": `${authHeader}`}}; + let request = http.get(url, params); + + check(request, { + "Successful authentication.": (r) => r.status === 200 + }); + + sleep(SLEEP_DURATION); + } + + // Request No. 2: + { + let url = BASE_URL + `/bearer`; + let request = http.get(url); + + check(request, { + "Unsuccessful authentication.": (r) => r.status === 401 + }); + } + }); + + group("/redirect-to", () => { + let redirectURL = 'https://example.com/'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let statusCode = '302'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let url = BASE_URL + `/redirect-to?url=${redirectURL}&status_code=${statusCode}`; + let request = http.get(url); + + check(request, { + "status is 200": (r) => r.status === 200 + }); + } + }); + + group("/image/svg", () => { + + // Request No. 1: + { + let url = BASE_URL + `/image/svg`; + let request = http.get(url); + + check(request, { + "An SVG image.": (r) => r.status === 200 + }); + } + }); + + group("/patch", () => { + + // Request No. 1: + { + let url = BASE_URL + `/patch`; + let request = http.patch(url); + + check(request, { + "The request's PATCH parameters.": (r) => r.status === 200 + }); + } + }); + + group("/deflate", () => { + + // Request No. 1: + { + let url = BASE_URL + `/deflate`; + let request = http.get(url); + + check(request, { + "Deflate-encoded data.": (r) => r.status === 200 + }); + } + }); + + group("/digest-auth/{qop}/{user}/{passwd}/{algorithm}", () => { + let qop = 'auth'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let passwd = 'password'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let user = 'user'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + let algorithm = 'MD5'; // extracted from 'example' field defined at the parameter level of OpenAPI spec + + // Request No. 1: + { + let parsedURL = new URL(BASE_URL); + parsedURL.username = user; + parsedURL.password = passwd; + parsedURL.pathname = `/digest-auth/${qop}/${user}/${passwd}/${algorithm}`; + + let url = parsedURL.toString(); + let params = {auth: "digest"}; + let request = http.get(url, params); + + check(request, { + "status is 200": (r) => r.status === 200, + "is authenticated": (r) => r.json().authenticated === true, + "is correct user": (r) => r.json().user === user, + }); + } + }); + + group("/robots.txt", () => { + + // Request No. 1: + { + let url = BASE_URL + `/robots.txt`; + let request = http.get(url); + + check(request, { + "Robots file": (r) => r.status === 200 + }); + } + }); + + group("/deny", () => { + + // Request No. 1: + { + let url = BASE_URL + `/deny`; + let request = http.get(url); + + check(request, { + "Denied message": (r) => r.status === 200 + }); + } + }); + +}