@grafana/openapi-to-k6 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.eslintrc.json +31 -0
  2. package/.github/workflows/publish.yaml +37 -0
  3. package/.github/workflows/tests.yaml +43 -0
  4. package/.husky/pre-commit +1 -0
  5. package/.nvmrc +1 -0
  6. package/.prettierrc +10 -0
  7. package/LICENSE.md +660 -0
  8. package/README.md +80 -0
  9. package/dist/analytics.js +80 -0
  10. package/dist/cli.js +84 -0
  11. package/dist/constants.js +21 -0
  12. package/dist/generator.js +57 -0
  13. package/dist/helper.js +198 -0
  14. package/dist/k6SdkClient.js +307 -0
  15. package/dist/logger.js +50 -0
  16. package/jest.config.js +15 -0
  17. package/package.json +56 -0
  18. package/src/analytics.ts +71 -0
  19. package/src/cli.ts +96 -0
  20. package/src/constants.ts +19 -0
  21. package/src/generator.ts +71 -0
  22. package/src/helper.ts +210 -0
  23. package/src/k6SdkClient.ts +434 -0
  24. package/src/logger.ts +61 -0
  25. package/src/type.d.ts +34 -0
  26. package/tests/e2e/k6Script.ts +77 -0
  27. package/tests/e2e/schema.json +289 -0
  28. package/tests/functional-tests/fixtures/schemas/basic_schema.json +41 -0
  29. package/tests/functional-tests/fixtures/schemas/form_data_schema.json +94 -0
  30. package/tests/functional-tests/fixtures/schemas/form_url_encoded_data_schema.json +93 -0
  31. package/tests/functional-tests/fixtures/schemas/form_url_encoded_data_with_query_params_schema.json +113 -0
  32. package/tests/functional-tests/fixtures/schemas/get_request_with_path_parameters_schema.json +66 -0
  33. package/tests/functional-tests/fixtures/schemas/headers_schema.json +163 -0
  34. package/tests/functional-tests/fixtures/schemas/no_title_schema.json +40 -0
  35. package/tests/functional-tests/fixtures/schemas/post_request_with_query_params.json +95 -0
  36. package/tests/functional-tests/fixtures/schemas/query_params_schema.json +115 -0
  37. package/tests/functional-tests/fixtures/schemas/simple_post_request_schema.json +132 -0
  38. package/tests/functional-tests/generator.test.ts +73 -0
  39. package/tests/helper.test.ts +203 -0
  40. package/tsconfig.json +17 -0
package/src/type.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ export interface PackageDetails {
2
+ name: string
3
+ commandName: string
4
+ description: string
5
+ version: string
6
+ }
7
+
8
+ export interface SchemaDetails {
9
+ title: string
10
+ }
11
+
12
+ export interface AnalyticsData {
13
+ generatedRequestsCount: {
14
+ post: number
15
+ put: number
16
+ get: number
17
+ delete: number
18
+ patch: number
19
+ head: number
20
+ }
21
+ openApiSpecVersion: string
22
+ toolVersion: string
23
+ anonymousUserId: string
24
+ osPlatform?: string
25
+ osArch?: string
26
+ osType?: string
27
+ }
28
+
29
+ export interface GenerateK6SDKOptions {
30
+ openApiPath: string
31
+ outputDir: string
32
+ shouldGenerateSampleK6Script?: boolean
33
+ analyticsData?: AnalyticsData
34
+ }
@@ -0,0 +1,77 @@
1
+ /* eslint-disable import/no-unresolved */
2
+ import { check } from 'k6'
3
+ import { createComprehensiveAPI } from './sdk.ts'
4
+ /* eslint-enable import/no-unresolved */
5
+
6
+ const baseUrl = 'http://localhost:3000'
7
+ const client = createComprehensiveAPI({ baseUrl })
8
+
9
+ export const options = {
10
+ thresholds: {
11
+ // the rate of successful checks should be higher than 90%
12
+ checks: ['rate>=1'],
13
+ },
14
+ }
15
+
16
+ function checkResponseStatus(response, expectedStatus) {
17
+ const result = check(response, {
18
+ [`status is ${expectedStatus}`]: (r) => r.status === expectedStatus,
19
+ })
20
+
21
+ if (!result) {
22
+ console.error(
23
+ `Check failed! Expected status ${expectedStatus} but got ${response.status}. Following is the response:`
24
+ )
25
+ console.log(JSON.stringify(response, null, 2))
26
+ }
27
+ }
28
+
29
+ export default function () {
30
+ const getResponseData = client.getItemsId('1')
31
+ checkResponseStatus(getResponseData.response, 200)
32
+
33
+ const postResponseData = client.postItemsId('1', {
34
+ name: 'string',
35
+ })
36
+ checkResponseStatus(postResponseData.response, 201)
37
+
38
+ const putResponseData = client.putItemsId('1', {
39
+ description: 'string',
40
+ })
41
+ checkResponseStatus(putResponseData.response, 200)
42
+
43
+ const deleteResponseData = client.deleteItemsId('1')
44
+ checkResponseStatus(deleteResponseData.response, 204)
45
+
46
+ const patchResponseData = client.patchItemsId('1', {
47
+ name: 'string',
48
+ })
49
+ checkResponseStatus(patchResponseData.response, 200)
50
+
51
+ const headResponseData = client.headItemsId('1')
52
+ checkResponseStatus(headResponseData.response, 200)
53
+
54
+ const postFormUrlEncodedResponseData = client.postItemsFormUrlEncoded({
55
+ name: 'string',
56
+ })
57
+ checkResponseStatus(postFormUrlEncodedResponseData.response, 201)
58
+ // Should add x-www-form-urlencoded content type header in request
59
+ check(postFormUrlEncodedResponseData.response, {
60
+ 'has x-www-form-urlencoded content type header': (r) =>
61
+ r.request.headers['Content-Type'][0] ===
62
+ 'application/x-www-form-urlencoded',
63
+ })
64
+
65
+ const postFormDataResponseData = client.postItemsFormData({
66
+ name: 'string',
67
+ })
68
+ checkResponseStatus(postFormDataResponseData.response, 201)
69
+
70
+ // Should add multipart/form-data content type header in request with boundary
71
+ check(postFormDataResponseData.response, {
72
+ 'has multipart/form-data content type header with bounday': (r) =>
73
+ r.request.headers['Content-Type'][0].includes(
74
+ 'multipart/form-data; boundary=---'
75
+ ),
76
+ })
77
+ }
@@ -0,0 +1,289 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "Comprehensive API",
5
+ "version": "1.0.0",
6
+ "description": "API supporting various HTTP methods with query, path parameters, and headers"
7
+ },
8
+ "paths": {
9
+ "/items/{id}": {
10
+ "get": {
11
+ "summary": "Get an item by ID",
12
+ "parameters": [
13
+ {
14
+ "name": "id",
15
+ "in": "path",
16
+ "required": true,
17
+ "description": "ID of the item to retrieve",
18
+ "schema": {
19
+ "type": "string"
20
+ }
21
+ },
22
+ {
23
+ "name": "detail",
24
+ "in": "query",
25
+ "required": false,
26
+ "description": "Whether to return detailed information",
27
+ "schema": {
28
+ "type": "boolean",
29
+ "default": false
30
+ }
31
+ }
32
+ ],
33
+ "responses": {
34
+ "200": {
35
+ "description": "Successful response"
36
+ }
37
+ }
38
+ },
39
+ "post": {
40
+ "summary": "Create an item by ID",
41
+ "parameters": [
42
+ {
43
+ "name": "id",
44
+ "in": "path",
45
+ "required": true,
46
+ "description": "ID of the item to create",
47
+ "schema": {
48
+ "type": "string"
49
+ }
50
+ }
51
+ ],
52
+ "requestBody": {
53
+ "required": true,
54
+ "content": {
55
+ "application/json": {
56
+ "schema": {
57
+ "type": "object",
58
+ "properties": {
59
+ "name": {
60
+ "type": "string"
61
+ },
62
+ "description": {
63
+ "type": "string"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ },
70
+ "responses": {
71
+ "201": {
72
+ "description": "Item created successfully"
73
+ }
74
+ }
75
+ },
76
+ "put": {
77
+ "summary": "Update an item by ID",
78
+ "parameters": [
79
+ {
80
+ "name": "id",
81
+ "in": "path",
82
+ "required": true,
83
+ "description": "ID of the item to update",
84
+ "schema": {
85
+ "type": "string"
86
+ }
87
+ }
88
+ ],
89
+ "requestBody": {
90
+ "required": true,
91
+ "content": {
92
+ "application/json": {
93
+ "schema": {
94
+ "type": "object",
95
+ "properties": {
96
+ "name": {
97
+ "type": "string"
98
+ },
99
+ "description": {
100
+ "type": "string"
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ },
107
+ "responses": {
108
+ "200": {
109
+ "description": "Item updated successfully"
110
+ }
111
+ }
112
+ },
113
+ "patch": {
114
+ "summary": "Partially update an item by ID",
115
+ "parameters": [
116
+ {
117
+ "name": "id",
118
+ "in": "path",
119
+ "required": true,
120
+ "description": "ID of the item to partially update",
121
+ "schema": {
122
+ "type": "string"
123
+ }
124
+ }
125
+ ],
126
+ "requestBody": {
127
+ "required": true,
128
+ "content": {
129
+ "application/json": {
130
+ "schema": {
131
+ "type": "object",
132
+ "properties": {
133
+ "name": {
134
+ "type": "string"
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ },
141
+ "responses": {
142
+ "200": {
143
+ "description": "Item partially updated"
144
+ }
145
+ }
146
+ },
147
+ "delete": {
148
+ "summary": "Delete an item by ID",
149
+ "parameters": [
150
+ {
151
+ "name": "id",
152
+ "in": "path",
153
+ "required": true,
154
+ "description": "ID of the item to delete",
155
+ "schema": {
156
+ "type": "string"
157
+ }
158
+ }
159
+ ],
160
+ "responses": {
161
+ "204": {
162
+ "description": "Item deleted successfully"
163
+ }
164
+ }
165
+ },
166
+ "head": {
167
+ "summary": "Check if item exists",
168
+ "parameters": [
169
+ {
170
+ "name": "id",
171
+ "in": "path",
172
+ "required": true,
173
+ "description": "ID of the item to check",
174
+ "schema": {
175
+ "type": "string"
176
+ }
177
+ }
178
+ ],
179
+ "responses": {
180
+ "200": {
181
+ "description": "Item exists"
182
+ },
183
+ "404": {
184
+ "description": "Item not found"
185
+ }
186
+ }
187
+ }
188
+ },
189
+ "/items-form-url-encoded": {
190
+ "post": {
191
+ "summary": "Create an item using form-urlencoded data",
192
+ "requestBody": {
193
+ "required": true,
194
+ "content": {
195
+ "application/x-www-form-urlencoded": {
196
+ "schema": {
197
+ "type": "object",
198
+ "properties": {
199
+ "name": {
200
+ "type": "string"
201
+ },
202
+ "description": {
203
+ "type": "string"
204
+ }
205
+ },
206
+ "required": ["name"]
207
+ }
208
+ }
209
+ }
210
+ },
211
+ "responses": {
212
+ "201": {
213
+ "description": "Item created successfully"
214
+ }
215
+ }
216
+ }
217
+ },
218
+ "/items-form-data": {
219
+ "post": {
220
+ "summary": "Create an item using form-data",
221
+ "requestBody": {
222
+ "required": true,
223
+ "content": {
224
+ "multipart/form-data": {
225
+ "schema": {
226
+ "type": "object",
227
+ "properties": {
228
+ "name": {
229
+ "type": "string"
230
+ }
231
+ },
232
+ "required": ["file", "name"]
233
+ }
234
+ }
235
+ }
236
+ },
237
+ "responses": {
238
+ "201": {
239
+ "description": "Item created with file upload"
240
+ }
241
+ }
242
+ }
243
+ },
244
+ "/items-header": {
245
+ "get": {
246
+ "summary": "Get an item with custom headers",
247
+ "parameters": [
248
+ {
249
+ "name": "id",
250
+ "in": "query",
251
+ "required": true,
252
+ "description": "ID of the item to retrieve",
253
+ "schema": {
254
+ "type": "string"
255
+ }
256
+ }
257
+ ],
258
+ "responses": {
259
+ "200": {
260
+ "description": "Item retrieved successfully"
261
+ }
262
+ },
263
+ "requestBody": {
264
+ "required": false
265
+ },
266
+ "headers": [
267
+ {
268
+ "name": "X-Client-ID",
269
+ "in": "header",
270
+ "description": "Client ID for the request",
271
+ "required": true,
272
+ "schema": {
273
+ "type": "string"
274
+ }
275
+ },
276
+ {
277
+ "name": "X-Request-ID",
278
+ "in": "header",
279
+ "description": "Unique request identifier",
280
+ "required": false,
281
+ "schema": {
282
+ "type": "string"
283
+ }
284
+ }
285
+ ]
286
+ }
287
+ }
288
+ }
289
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "openapi_schema": {
3
+ "openapi": "3.0.0",
4
+ "info": {
5
+ "title": "Simple API",
6
+ "version": "1.0.0"
7
+ },
8
+ "paths": {
9
+ "/example": {
10
+ "get": {
11
+ "summary": "Retrieve example data",
12
+ "responses": {
13
+ "200": {
14
+ "description": "Successful response",
15
+ "content": {
16
+ "application/json": {
17
+ "schema": {
18
+ "type": "object",
19
+ "properties": {
20
+ "message": {
21
+ "type": "string",
22
+ "example": "Hello, World!"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ },
34
+ "expected_sdk": {
35
+ "fileName": "simpleAPI.ts",
36
+ "expectedSubstrings": [
37
+ "export const createSimpleAPI =",
38
+ "return { getExample };"
39
+ ]
40
+ }
41
+ }
@@ -0,0 +1,94 @@
1
+ {
2
+ "openapi_schema": {
3
+ "openapi": "3.0.0",
4
+ "info": {
5
+ "title": "Form Data API",
6
+ "version": "1.0.0"
7
+ },
8
+ "paths": {
9
+ "/upload": {
10
+ "post": {
11
+ "summary": "Upload files and data",
12
+ "description": "This endpoint accepts form data and file uploads.",
13
+ "requestBody": {
14
+ "required": true,
15
+ "content": {
16
+ "multipart/form-data": {
17
+ "schema": {
18
+ "type": "object",
19
+ "properties": {
20
+ "file": {
21
+ "type": "string",
22
+ "format": "binary",
23
+ "description": "File to upload"
24
+ },
25
+ "description": {
26
+ "type": "string",
27
+ "description": "Description of the file"
28
+ },
29
+ "userId": {
30
+ "type": "string",
31
+ "description": "User ID associated with the upload"
32
+ }
33
+ },
34
+ "required": ["file", "userId"]
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "responses": {
40
+ "200": {
41
+ "description": "File uploaded successfully",
42
+ "content": {
43
+ "application/json": {
44
+ "schema": {
45
+ "type": "object",
46
+ "properties": {
47
+ "success": {
48
+ "type": "boolean",
49
+ "example": true
50
+ },
51
+ "message": {
52
+ "type": "string",
53
+ "example": "File uploaded successfully"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ },
60
+ "400": {
61
+ "description": "Bad Request",
62
+ "content": {
63
+ "application/json": {
64
+ "schema": {
65
+ "type": "object",
66
+ "properties": {
67
+ "success": {
68
+ "type": "boolean",
69
+ "example": false
70
+ },
71
+ "error": {
72
+ "type": "string",
73
+ "example": "Invalid file or data"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ },
85
+ "expected_sdk": {
86
+ "fileName": "formDataAPI.ts",
87
+ "expectedSubstrings": [
88
+ "export const createFormDataAPI = (clientOptions: CreateFormDataAPIOptions) => {",
89
+ "const formData = new FormData();\n formData.append(\"file\", postUploadBody.file);\n if (postUploadBody.description !== undefined) {\n formData.append(\"description\", postUploadBody.description);\n }\n formData.append(\"userId\", postUploadBody.userId);",
90
+ "const url = new URL(cleanBaseUrl + `/upload`);",
91
+ "const response = http.request(\"POST\", url.toString(), formData.body(), {\n ...mergedRequestParameters,\n headers: {\n \"Content-Type\": \"multipart/form-data; boundary=\" + formData.boundary,\n ...mergedRequestParameters?.headers,\n },\n });"
92
+ ]
93
+ }
94
+ }
@@ -0,0 +1,93 @@
1
+ {
2
+ "openapi_schema": {
3
+ "openapi": "3.0.0",
4
+ "info": {
5
+ "title": "Form URL Encoded API",
6
+ "version": "1.0.0"
7
+ },
8
+ "paths": {
9
+ "/submit-form": {
10
+ "post": {
11
+ "summary": "Submit form data",
12
+ "description": "This endpoint accepts form URL-encoded data.",
13
+ "requestBody": {
14
+ "required": true,
15
+ "content": {
16
+ "application/x-www-form-urlencoded": {
17
+ "schema": {
18
+ "type": "object",
19
+ "properties": {
20
+ "name": {
21
+ "type": "string",
22
+ "description": "Name of the user"
23
+ },
24
+ "age": {
25
+ "type": "integer",
26
+ "description": "Age of the user"
27
+ },
28
+ "email": {
29
+ "type": "string",
30
+ "format": "email",
31
+ "description": "Email address of the user"
32
+ }
33
+ },
34
+ "required": ["name", "email"]
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "responses": {
40
+ "200": {
41
+ "description": "Form submitted successfully",
42
+ "content": {
43
+ "application/json": {
44
+ "schema": {
45
+ "type": "object",
46
+ "properties": {
47
+ "success": {
48
+ "type": "boolean",
49
+ "example": true
50
+ },
51
+ "message": {
52
+ "type": "string",
53
+ "example": "Form submitted successfully"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ },
60
+ "400": {
61
+ "description": "Bad Request",
62
+ "content": {
63
+ "application/json": {
64
+ "schema": {
65
+ "type": "object",
66
+ "properties": {
67
+ "success": {
68
+ "type": "boolean",
69
+ "example": false
70
+ },
71
+ "error": {
72
+ "type": "string",
73
+ "example": "Invalid input data"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ },
85
+ "expected_sdk": {
86
+ "fileName": "formURLEncodedAPI.ts",
87
+ "expectedSubstrings": [
88
+ "export const createFormURLEncodedAPI = (\n clientOptions: CreateFormURLEncodedAPIOptions,\n) => {",
89
+ "const url = new URL(cleanBaseUrl + `/submit-form`);",
90
+ "const response = http.request(\n \"POST\",\n url.toString(),\n JSON.stringify(postSubmitFormBody),\n {\n ...mergedRequestParameters,\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n ...mergedRequestParameters?.headers,\n },\n },\n );"
91
+ ]
92
+ }
93
+ }