@atom8n/n8n-benchmark 2.0.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 (158) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/Dockerfile +63 -0
  3. package/README.md +122 -0
  4. package/bin/n8n-benchmark +13 -0
  5. package/biome.jsonc +7 -0
  6. package/dist/build.tsbuildinfo +1 -0
  7. package/dist/commands/list.d.ts +8 -0
  8. package/dist/commands/list.js +23 -0
  9. package/dist/commands/list.js.map +1 -0
  10. package/dist/commands/run.d.ts +24 -0
  11. package/dist/commands/run.js +128 -0
  12. package/dist/commands/run.js.map +1 -0
  13. package/dist/config/common-flags.d.ts +1 -0
  14. package/dist/config/common-flags.js +9 -0
  15. package/dist/config/common-flags.js.map +1 -0
  16. package/dist/n8n-api-client/authenticated-n8n-api-client.d.ts +15 -0
  17. package/dist/n8n-api-client/authenticated-n8n-api-client.js +67 -0
  18. package/dist/n8n-api-client/authenticated-n8n-api-client.js.map +1 -0
  19. package/dist/n8n-api-client/credentials-api-client.d.ts +9 -0
  20. package/dist/n8n-api-client/credentials-api-client.js +24 -0
  21. package/dist/n8n-api-client/credentials-api-client.js.map +1 -0
  22. package/dist/n8n-api-client/data-table-api-client.d.ts +9 -0
  23. package/dist/n8n-api-client/data-table-api-client.js +23 -0
  24. package/dist/n8n-api-client/data-table-api-client.js.map +1 -0
  25. package/dist/n8n-api-client/n8n-api-client.d.ts +13 -0
  26. package/dist/n8n-api-client/n8n-api-client.js +82 -0
  27. package/dist/n8n-api-client/n8n-api-client.js.map +1 -0
  28. package/dist/n8n-api-client/n8n-api-client.types.d.ts +21 -0
  29. package/dist/n8n-api-client/n8n-api-client.types.js +3 -0
  30. package/dist/n8n-api-client/n8n-api-client.types.js.map +1 -0
  31. package/dist/n8n-api-client/project-api-client.d.ts +6 -0
  32. package/dist/n8n-api-client/project-api-client.js +14 -0
  33. package/dist/n8n-api-client/project-api-client.js.map +1 -0
  34. package/dist/n8n-api-client/workflows-api-client.d.ts +11 -0
  35. package/dist/n8n-api-client/workflows-api-client.js +30 -0
  36. package/dist/n8n-api-client/workflows-api-client.js.map +1 -0
  37. package/dist/scenario/scenario-data-loader.d.ts +13 -0
  38. package/dist/scenario/scenario-data-loader.js +84 -0
  39. package/dist/scenario/scenario-data-loader.js.map +1 -0
  40. package/dist/scenario/scenario-loader.d.ts +7 -0
  41. package/dist/scenario/scenario-loader.js +101 -0
  42. package/dist/scenario/scenario-loader.js.map +1 -0
  43. package/dist/test-execution/app-metrics-poller.d.ts +13 -0
  44. package/dist/test-execution/app-metrics-poller.js +54 -0
  45. package/dist/test-execution/app-metrics-poller.js.map +1 -0
  46. package/dist/test-execution/k6-executor.d.ts +33 -0
  47. package/dist/test-execution/k6-executor.js +120 -0
  48. package/dist/test-execution/k6-executor.js.map +1 -0
  49. package/dist/test-execution/k6-summary.d.ts +82 -0
  50. package/dist/test-execution/k6-summary.js +2 -0
  51. package/dist/test-execution/k6-summary.js.map +1 -0
  52. package/dist/test-execution/prometheus-metrics-parser.d.ts +9 -0
  53. package/dist/test-execution/prometheus-metrics-parser.js +44 -0
  54. package/dist/test-execution/prometheus-metrics-parser.js.map +1 -0
  55. package/dist/test-execution/scenario-data-importer.d.ts +21 -0
  56. package/dist/test-execution/scenario-data-importer.js +108 -0
  57. package/dist/test-execution/scenario-data-importer.js.map +1 -0
  58. package/dist/test-execution/scenario-runner.d.ts +18 -0
  59. package/dist/test-execution/scenario-runner.js +46 -0
  60. package/dist/test-execution/scenario-runner.js.map +1 -0
  61. package/dist/test-execution/test-report.d.ts +56 -0
  62. package/dist/test-execution/test-report.js +65 -0
  63. package/dist/test-execution/test-report.js.map +1 -0
  64. package/dist/types/scenario.d.ts +16 -0
  65. package/dist/types/scenario.js +3 -0
  66. package/dist/types/scenario.js.map +1 -0
  67. package/eslint.config.mjs +22 -0
  68. package/infra/.terraform.lock.hcl +60 -0
  69. package/infra/benchmark-env.tf +54 -0
  70. package/infra/modules/benchmark-vm/output.tf +11 -0
  71. package/infra/modules/benchmark-vm/vars.tf +29 -0
  72. package/infra/modules/benchmark-vm/vm.tf +126 -0
  73. package/infra/output.tf +16 -0
  74. package/infra/providers.tf +23 -0
  75. package/infra/vars.tf +34 -0
  76. package/package.json +55 -0
  77. package/scenarios/binary-data/binary-data.json +67 -0
  78. package/scenarios/binary-data/binary-data.manifest.json +7 -0
  79. package/scenarios/binary-data/binary-data.script.js +29 -0
  80. package/scenarios/credential-http-node/credential-bearer.json +8 -0
  81. package/scenarios/credential-http-node/credential-http-node.json +241 -0
  82. package/scenarios/credential-http-node/credential-http-node.manifest.json +10 -0
  83. package/scenarios/credential-http-node/credential-http-node.script.js +30 -0
  84. package/scenarios/data-table-node/data-table-node.json +168 -0
  85. package/scenarios/data-table-node/data-table-node.manifest.json +10 -0
  86. package/scenarios/data-table-node/data-table-node.script.js +38 -0
  87. package/scenarios/data-table-node/data-table.json +25 -0
  88. package/scenarios/http-node/http-node.json +213 -0
  89. package/scenarios/http-node/http-node.manifest.json +7 -0
  90. package/scenarios/http-node/http-node.script.js +30 -0
  91. package/scenarios/js-code-node/js-code-node.json +96 -0
  92. package/scenarios/js-code-node/js-code-node.manifest.json +7 -0
  93. package/scenarios/js-code-node/js-code-node.script.js +29 -0
  94. package/scenarios/multiple-webhooks/multiple-webhooks.manifest.json +20 -0
  95. package/scenarios/multiple-webhooks/multiple-webhooks.script.js +19 -0
  96. package/scenarios/multiple-webhooks/multiple-webhooks1.json +25 -0
  97. package/scenarios/multiple-webhooks/multiple-webhooks10.json +25 -0
  98. package/scenarios/multiple-webhooks/multiple-webhooks2.json +25 -0
  99. package/scenarios/multiple-webhooks/multiple-webhooks3.json +25 -0
  100. package/scenarios/multiple-webhooks/multiple-webhooks4.json +25 -0
  101. package/scenarios/multiple-webhooks/multiple-webhooks5.json +25 -0
  102. package/scenarios/multiple-webhooks/multiple-webhooks6.json +25 -0
  103. package/scenarios/multiple-webhooks/multiple-webhooks7.json +25 -0
  104. package/scenarios/multiple-webhooks/multiple-webhooks8.json +25 -0
  105. package/scenarios/multiple-webhooks/multiple-webhooks9.json +25 -0
  106. package/scenarios/py-code-node/py-code-node.json +98 -0
  107. package/scenarios/py-code-node/py-code-node.manifest.json +7 -0
  108. package/scenarios/py-code-node/py-code-node.script.js +29 -0
  109. package/scenarios/scenario.schema.json +51 -0
  110. package/scenarios/set-node-expressions/set-node-expressions.json +91 -0
  111. package/scenarios/set-node-expressions/set-node-expressions.manifest.json +7 -0
  112. package/scenarios/set-node-expressions/set-node-expressions.script.js +18 -0
  113. package/scenarios/single-webhook/single-webhook.json +25 -0
  114. package/scenarios/single-webhook/single-webhook.manifest.json +7 -0
  115. package/scenarios/single-webhook/single-webhook.script.js +18 -0
  116. package/scripts/bootstrap.sh +63 -0
  117. package/scripts/clients/docker-compose-client.mjs +45 -0
  118. package/scripts/clients/ssh-client.mjs +37 -0
  119. package/scripts/clients/terraform-client.mjs +71 -0
  120. package/scripts/destroy-cloud-env.mjs +86 -0
  121. package/scripts/mock-api/mappings/mockApiData.json +92110 -0
  122. package/scripts/n8n-setups/postgres/docker-compose.yml +76 -0
  123. package/scripts/n8n-setups/postgres/setup.mjs +15 -0
  124. package/scripts/n8n-setups/scaling-multi-main/docker-compose.yml +230 -0
  125. package/scripts/n8n-setups/scaling-multi-main/nginx.conf +24 -0
  126. package/scripts/n8n-setups/scaling-multi-main/setup.mjs +15 -0
  127. package/scripts/n8n-setups/scaling-single-main/docker-compose.yml +174 -0
  128. package/scripts/n8n-setups/scaling-single-main/setup.mjs +15 -0
  129. package/scripts/n8n-setups/sqlite/docker-compose.yml +55 -0
  130. package/scripts/n8n-setups/sqlite/setup.mjs +15 -0
  131. package/scripts/provision-cloud-env.mjs +36 -0
  132. package/scripts/run-for-n8n-setup.mjs +175 -0
  133. package/scripts/run-in-cloud.mjs +167 -0
  134. package/scripts/run-locally.mjs +73 -0
  135. package/scripts/run.mjs +192 -0
  136. package/scripts/utils/flags.mjs +20 -0
  137. package/src/commands/list.ts +26 -0
  138. package/src/commands/run.ts +140 -0
  139. package/src/config/common-flags.ts +6 -0
  140. package/src/n8n-api-client/authenticated-n8n-api-client.ts +88 -0
  141. package/src/n8n-api-client/credentials-api-client.ts +28 -0
  142. package/src/n8n-api-client/data-table-api-client.ts +30 -0
  143. package/src/n8n-api-client/n8n-api-client.ts +85 -0
  144. package/src/n8n-api-client/n8n-api-client.types.ts +27 -0
  145. package/src/n8n-api-client/project-api-client.ts +11 -0
  146. package/src/n8n-api-client/workflows-api-client.ts +38 -0
  147. package/src/scenario/scenario-data-loader.ts +75 -0
  148. package/src/scenario/scenario-loader.ts +90 -0
  149. package/src/test-execution/app-metrics-poller.ts +81 -0
  150. package/src/test-execution/k6-executor.ts +192 -0
  151. package/src/test-execution/k6-summary.ts +255 -0
  152. package/src/test-execution/prometheus-metrics-parser.ts +63 -0
  153. package/src/test-execution/scenario-data-importer.ts +165 -0
  154. package/src/test-execution/scenario-runner.ts +76 -0
  155. package/src/test-execution/test-report.ts +152 -0
  156. package/src/types/scenario.ts +33 -0
  157. package/tsconfig.build.json +9 -0
  158. package/tsconfig.json +14 -0
@@ -0,0 +1,241 @@
1
+ {
2
+ "name": "Credential HTTP Request",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "httpMethod": "POST",
7
+ "path": "benchmark-credential-http-node",
8
+ "responseMode": "responseNode",
9
+ "options": {}
10
+ },
11
+ "type": "n8n-nodes-base.webhook",
12
+ "typeVersion": 2,
13
+ "position": [-64, 32],
14
+ "id": "7dd66dcc-03c7-4898-ab3d-d2765730e3f3",
15
+ "name": "Webhook",
16
+ "webhookId": "92b141cd-6e59-4425-9c0a-e2ee0f4faad2"
17
+ },
18
+ {
19
+ "parameters": {
20
+ "respondWith": "allIncomingItems",
21
+ "options": {}
22
+ },
23
+ "type": "n8n-nodes-base.respondToWebhook",
24
+ "typeVersion": 1.1,
25
+ "position": [1072, 32],
26
+ "id": "e074e6a7-2417-4fde-8b6b-bc68069e833b",
27
+ "name": "Respond to Webhook"
28
+ },
29
+ {
30
+ "parameters": {
31
+ "url": "http://mockapi:8080/users/clair.bahringer/received_events/public",
32
+ "authentication": "genericCredentialType",
33
+ "genericAuthType": "httpBearerAuth",
34
+ "options": {
35
+ "response": {
36
+ "response": {
37
+ "fullResponse": true
38
+ }
39
+ }
40
+ }
41
+ },
42
+ "type": "n8n-nodes-base.httpRequest",
43
+ "typeVersion": 4.2,
44
+ "position": [304, -176],
45
+ "id": "28ddbbf9-56a5-431e-afe9-3c44b21aa676",
46
+ "name": "Mock public received events",
47
+ "credentials": {
48
+ "httpBearerAuth": {
49
+ "id": "0fqzOReozl2aQvtl",
50
+ "name": "Dummy HTTP credential"
51
+ }
52
+ }
53
+ },
54
+ {
55
+ "parameters": {
56
+ "url": "http://mockapi:8080/repos/udke6pujoywnagxkcvab2riw23khzn2tibo2vincws32qexb50ey7h97d42vnzyol0rxypgsg4pomsf7sgnmdaihstljw8edcijrwmy7mfi76yif19c4/47i31dh737el215j62ts2f2782nw3ss26rul3s8jw13u3vu0xm349a5hyay5asmwnlnf7nx8p9h4g62so6s1cis7xv9puj5j98t4m980sbe2455fn1obccjl/events",
57
+ "authentication": "genericCredentialType",
58
+ "genericAuthType": "httpBearerAuth",
59
+ "options": {
60
+ "response": {
61
+ "response": {
62
+ "fullResponse": true
63
+ }
64
+ }
65
+ }
66
+ },
67
+ "type": "n8n-nodes-base.httpRequest",
68
+ "typeVersion": 4.2,
69
+ "position": [304, 32],
70
+ "id": "3ce8827c-6226-467e-a4da-9891c1acd863",
71
+ "name": "Mock repository events",
72
+ "credentials": {
73
+ "httpBearerAuth": {
74
+ "id": "0fqzOReozl2aQvtl",
75
+ "name": "Dummy HTTP credential"
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "parameters": {
81
+ "url": "http://mockapi:8080/orgs/g02pp066qoyithcjevhd6m1wfii3c4x51k39n9apybljhx69/events",
82
+ "authentication": "genericCredentialType",
83
+ "genericAuthType": "httpBearerAuth",
84
+ "options": {
85
+ "response": {
86
+ "response": {
87
+ "fullResponse": true
88
+ }
89
+ }
90
+ }
91
+ },
92
+ "type": "n8n-nodes-base.httpRequest",
93
+ "typeVersion": 4.2,
94
+ "position": [304, 224],
95
+ "id": "a8e416ab-50cc-4e50-8d9a-9fcf5d4bbdc8",
96
+ "name": "Mock organization events",
97
+ "credentials": {
98
+ "httpBearerAuth": {
99
+ "id": "0fqzOReozl2aQvtl",
100
+ "name": "Dummy HTTP credential"
101
+ }
102
+ }
103
+ },
104
+ {
105
+ "parameters": {
106
+ "numberInputs": 3
107
+ },
108
+ "type": "n8n-nodes-base.merge",
109
+ "typeVersion": 3,
110
+ "position": [608, 32],
111
+ "id": "542a27d4-3a03-4c22-a79a-7266050c519e",
112
+ "name": "Merge"
113
+ },
114
+ {
115
+ "parameters": {
116
+ "assignments": {
117
+ "assignments": [
118
+ {
119
+ "id": "89608adb-f487-416f-a7d8-3ebb1f7b50e5",
120
+ "name": "statusCode",
121
+ "value": "={{ $json.statusCode }}",
122
+ "type": "number"
123
+ }
124
+ ]
125
+ },
126
+ "options": {}
127
+ },
128
+ "id": "35d4bfbb-d4be-49f4-a5dd-bd5c67a48200",
129
+ "name": "Select statusCode",
130
+ "type": "n8n-nodes-base.set",
131
+ "typeVersion": 3.4,
132
+ "position": [832, 32]
133
+ }
134
+ ],
135
+ "pinData": {
136
+ "Webhook": [
137
+ {
138
+ "json": {
139
+ "headers": {
140
+ "host": "localhost:5678",
141
+ "user-agent": "curl/8.6.0",
142
+ "accept": "*/*"
143
+ },
144
+ "params": {},
145
+ "query": {},
146
+ "body": {},
147
+ "webhookUrl": "http://localhost:5678/webhook-test/benchmark-credential-http-node",
148
+ "executionMode": "test"
149
+ }
150
+ }
151
+ ]
152
+ },
153
+ "connections": {
154
+ "Webhook": {
155
+ "main": [
156
+ [
157
+ {
158
+ "node": "Mock public received events",
159
+ "type": "main",
160
+ "index": 0
161
+ },
162
+ {
163
+ "node": "Mock repository events",
164
+ "type": "main",
165
+ "index": 0
166
+ },
167
+ {
168
+ "node": "Mock organization events",
169
+ "type": "main",
170
+ "index": 0
171
+ }
172
+ ]
173
+ ]
174
+ },
175
+ "Mock public received events": {
176
+ "main": [
177
+ [
178
+ {
179
+ "node": "Merge",
180
+ "type": "main",
181
+ "index": 0
182
+ }
183
+ ]
184
+ ]
185
+ },
186
+ "Mock repository events": {
187
+ "main": [
188
+ [
189
+ {
190
+ "node": "Merge",
191
+ "type": "main",
192
+ "index": 1
193
+ }
194
+ ]
195
+ ]
196
+ },
197
+ "Mock organization events": {
198
+ "main": [
199
+ [
200
+ {
201
+ "node": "Merge",
202
+ "type": "main",
203
+ "index": 2
204
+ }
205
+ ]
206
+ ]
207
+ },
208
+ "Merge": {
209
+ "main": [
210
+ [
211
+ {
212
+ "node": "Select statusCode",
213
+ "type": "main",
214
+ "index": 0
215
+ }
216
+ ]
217
+ ]
218
+ },
219
+ "Select statusCode": {
220
+ "main": [
221
+ [
222
+ {
223
+ "node": "Respond to Webhook",
224
+ "type": "main",
225
+ "index": 0
226
+ }
227
+ ]
228
+ ]
229
+ }
230
+ },
231
+ "active": false,
232
+ "settings": {
233
+ "executionOrder": "v1"
234
+ },
235
+ "versionId": "96bfc5ef-9421-47f5-9fdd-432dbd4bc4ca",
236
+ "meta": {
237
+ "instanceId": "4141065f11bd5ed73fef4f9b1d91842ded0ec4058e6640a98aa14384e269204b"
238
+ },
239
+ "id": "6V8rTiIDqZOniAs1",
240
+ "tags": []
241
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "../scenario.schema.json",
3
+ "name": "CredentialHttpNode",
4
+ "description": "Webhook -> 3x HTTP request to a mock API -> Merge -> Respond to Webhook. Requires a mock API running at http://mockapi:8080",
5
+ "scenarioData": {
6
+ "workflowFiles": ["credential-http-node.json"],
7
+ "credentialFiles": ["credential-bearer.json"]
8
+ },
9
+ "scriptPath": "credential-http-node.script.js"
10
+ }
@@ -0,0 +1,30 @@
1
+ import http from 'k6/http';
2
+ import { check } from 'k6';
3
+
4
+ const apiBaseUrl = __ENV.API_BASE_URL;
5
+
6
+ export default function () {
7
+ const res = http.post(`${apiBaseUrl}/webhook/benchmark-credential-http-node`);
8
+
9
+ if (res.status !== 200) {
10
+ console.error(
11
+ `Invalid response. Received status ${res.status}. Body: ${JSON.stringify(res.body)}`,
12
+ );
13
+ }
14
+
15
+ check(res, {
16
+ 'is status 200': (r) => r.status === 200,
17
+ 'http requests were OK': (r) => {
18
+ if (r.status !== 200) return false;
19
+
20
+ try {
21
+ // Response body is an array of the request status codes made with HttpNodes
22
+ const body = JSON.parse(r.body);
23
+ return Array.isArray(body) ? body.every((request) => request.statusCode === 200) : false;
24
+ } catch (error) {
25
+ console.error('Error parsing response body: ', error);
26
+ return false;
27
+ }
28
+ },
29
+ });
30
+ }
@@ -0,0 +1,168 @@
1
+ {
2
+ "createdAt": "2025-09-24T12:19:51.268Z",
3
+ "updatedAt": "2025-09-24T12:20:45.000Z",
4
+ "name": "Data table node",
5
+ "active": true,
6
+ "nodes": [
7
+ {
8
+ "parameters": {
9
+ "respondWith": "allIncomingItems",
10
+ "options": {}
11
+ },
12
+ "type": "n8n-nodes-base.respondToWebhook",
13
+ "typeVersion": 1.4,
14
+ "position": [688, 0],
15
+ "id": "a7eeb256-a47e-4fe9-a0e1-b33015912b15",
16
+ "name": "Respond to Webhook"
17
+ },
18
+ {
19
+ "parameters": {
20
+ "httpMethod": "POST",
21
+ "path": "data-table-node-benchmark",
22
+ "responseMode": "responseNode",
23
+ "options": {}
24
+ },
25
+ "type": "n8n-nodes-base.webhook",
26
+ "typeVersion": 2.1,
27
+ "position": [-288, 0],
28
+ "id": "b54681a1-6cfc-4970-ad33-25cb8fec6936",
29
+ "name": "Webhook",
30
+ "webhookId": "4748ca75-3b3c-4e4a-8913-3590fdc1867d"
31
+ },
32
+ {
33
+ "parameters": {
34
+ "fieldToSplitOut": "body.items",
35
+ "options": {}
36
+ },
37
+ "type": "n8n-nodes-base.splitOut",
38
+ "typeVersion": 1,
39
+ "position": [96, 0],
40
+ "id": "019d451f-604f-4ed6-8f40-1beb86445061",
41
+ "name": "Split Out"
42
+ },
43
+ {
44
+ "parameters": {
45
+ "dataTableId": {
46
+ "__rl": true,
47
+ "value": "={{ $('Webhook').item.json.body.dataTableId }}",
48
+ "mode": "list"
49
+ },
50
+ "columns": {
51
+ "mappingMode": "defineBelow",
52
+ "value": {
53
+ "isActive": "={{ $json.isActive }}",
54
+ "firstName": "={{ $json.firstName }}",
55
+ "birthDate": "={{ $json.birthDate }}",
56
+ "age": "={{ $json.age }}"
57
+ },
58
+ "matchingColumns": [],
59
+ "schema": [
60
+ {
61
+ "id": "firstName",
62
+ "displayName": "firstName",
63
+ "required": false,
64
+ "defaultMatch": false,
65
+ "display": true,
66
+ "type": "string",
67
+ "readOnly": false,
68
+ "removed": false
69
+ },
70
+ {
71
+ "id": "age",
72
+ "displayName": "age",
73
+ "required": false,
74
+ "defaultMatch": false,
75
+ "display": true,
76
+ "type": "number",
77
+ "readOnly": false,
78
+ "removed": false
79
+ },
80
+ {
81
+ "id": "birthDate",
82
+ "displayName": "birthDate",
83
+ "required": false,
84
+ "defaultMatch": false,
85
+ "display": true,
86
+ "type": "dateTime",
87
+ "readOnly": false,
88
+ "removed": false
89
+ },
90
+ {
91
+ "id": "isActive",
92
+ "displayName": "isActive",
93
+ "required": false,
94
+ "defaultMatch": false,
95
+ "display": true,
96
+ "type": "boolean",
97
+ "readOnly": false,
98
+ "removed": false
99
+ },
100
+ {
101
+ "id": "empty",
102
+ "displayName": "empty",
103
+ "required": false,
104
+ "defaultMatch": false,
105
+ "display": true,
106
+ "type": "string",
107
+ "readOnly": false,
108
+ "removed": false
109
+ }
110
+ ],
111
+ "attemptToConvertTypes": false,
112
+ "convertFieldsToString": false
113
+ },
114
+ "options": {}
115
+ },
116
+ "type": "n8n-nodes-base.dataTable",
117
+ "typeVersion": 1,
118
+ "position": [448, 0],
119
+ "id": "05a47403-6c7d-4aad-b0eb-ca726e7594c9",
120
+ "name": "Insert row"
121
+ }
122
+ ],
123
+ "connections": {
124
+ "Webhook": {
125
+ "main": [
126
+ [
127
+ {
128
+ "node": "Split Out",
129
+ "type": "main",
130
+ "index": 0
131
+ }
132
+ ]
133
+ ]
134
+ },
135
+ "Insert row": {
136
+ "main": [
137
+ [
138
+ {
139
+ "node": "Respond to Webhook",
140
+ "type": "main",
141
+ "index": 0
142
+ }
143
+ ]
144
+ ]
145
+ },
146
+ "Split Out": {
147
+ "main": [
148
+ [
149
+ {
150
+ "node": "Insert row",
151
+ "type": "main",
152
+ "index": 0
153
+ }
154
+ ]
155
+ ]
156
+ }
157
+ },
158
+ "pinData": {},
159
+ "settings": { "executionOrder": "v1" },
160
+ "staticData": null,
161
+ "versionId": "cdd59544-4b5d-42c0-a07f-8ab48a9d849c",
162
+ "triggerCount": 1,
163
+ "tags": [],
164
+ "meta": {
165
+ "responseMode": "lastNode",
166
+ "options": {}
167
+ }
168
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "../scenario.schema.json",
3
+ "name": "DataTableNode",
4
+ "description": "A Data table node that first inserts 100 items and then reads them from the table. The data is returned with RespondToWebhook Node.",
5
+ "scenarioData": {
6
+ "workflowFiles": ["data-table-node.json"],
7
+ "dataTableFile": "data-table.json"
8
+ },
9
+ "scriptPath": "data-table-node.script.js"
10
+ }
@@ -0,0 +1,38 @@
1
+ import http from 'k6/http';
2
+ import { check } from 'k6';
3
+
4
+ const apiBaseUrl = __ENV.API_BASE_URL;
5
+ const dataTableId = __ENV.DATA_TABLE_ID;
6
+
7
+ export default function () {
8
+ const res = http.post(`${apiBaseUrl}/webhook/data-table-node-benchmark`, {
9
+ dataTableId: dataTableId,
10
+ items: Array.from({ length: 100 }, (_, i) => ({
11
+ firstName: `Item ${i + 1}`,
12
+ age: Math.floor(Math.random() * 100),
13
+ birthDate: new Date(),
14
+ isActive: i % 2 === 0,
15
+ })),
16
+ });
17
+
18
+ if (res.status !== 200) {
19
+ console.error(
20
+ `Invalid response. Received status ${res.status}. Body: ${JSON.stringify(res.body)}`,
21
+ );
22
+ }
23
+
24
+ check(res, {
25
+ 'is status 200': (r) => r.status === 200,
26
+ 'has items in response': (r) => {
27
+ if (r.status !== 200) return false;
28
+
29
+ try {
30
+ const body = JSON.parse(r.body);
31
+ return Array.isArray(body) ? body.length === 100 : false;
32
+ } catch (error) {
33
+ console.error('Error parsing response body: ', error);
34
+ return false;
35
+ }
36
+ },
37
+ });
38
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "data-table-node-benchmark",
3
+ "columns": [
4
+ {
5
+ "name": "firstName",
6
+ "type": "string"
7
+ },
8
+ {
9
+ "name": "age",
10
+ "type": "number"
11
+ },
12
+ {
13
+ "name": "birthDate",
14
+ "type": "date"
15
+ },
16
+ {
17
+ "name": "isActive",
18
+ "type": "boolean"
19
+ },
20
+ {
21
+ "name": "empty",
22
+ "type": "string"
23
+ }
24
+ ]
25
+ }