-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathconfig_schema.json
556 lines (556 loc) · 31.7 KB
/
config_schema.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
{
"$schema":"http://json-schema.org/draft-04/schema#",
"description":" h2loadrunner configuration",
"title":"h2loadrunner_configuration",
"type":"object",
"properties":
{
"schema":
{
"description":"http, or https; to use TLS or mTLS, please choose https here",
"type":"string",
"default": "http",
"enum": ["http", "https"]
},
"host":
{
"description":"host to be tested with load, for example: 192.168.1.1, or, www.h2loadrunner.com",
"type":"string"
},
"port":
{
"description":"port, 80, 443 ,etc.",
"default": 80,
"type":"integer"
},
"load-share-hosts":
{
"description": "A list of hosts with optional ports, which together with host in host/port field above would be used as a load share group; h2loadrunner will distribute the connections evenly to each host of the group, so the test traffic is also evenly distributed to each host.",
"type":"array",
"minItems":0,
"items":
{
"type": "object",
"properties":
{
"host":
{
"description":"host part, for example: 192.168.1.1, or, www.h2loadrunner.com",
"type":"string"
},
"port":
{
"description":"port, 80, 443 ,etc.",
"default": 80,
"type":"integer"
}
},
"required":
[
"host"
]
}
},
"open-new-connection-based-on-authority-header":
{
"description": "false: h2loadrunner will stick to the connections created with host fields above, and create no dynamic connections; true: request should be routed to the host strictly matching the authority header, so h2loadrunner will create dynamic connections when necessary based on per request configuration (either from input or from previous response header), and route the requests based on the request authority header",
"default": false,
"type":"boolean"
},
"connection-retry":
{
"description": "false: upon disconnect from host, h2loadrunner will not try open new connection; true: h2loadrunner will try to open new connections upon host disconnect, either to another host in the load share group above, or to the same host if no other host is available; note: after reconnection is made due to peer disconnect, load balance is no longer guaranteed, see next field for more information",
"default": true,
"type":"boolean"
},
"switch-back-after-connection-retry":
{
"description": "when connection-retry occurs due to host disconnect, load balance may be broken as mentioned above; this field provide an option to recover; true: h2loadrunner will monitor the host disconnected, and when it is up again (tcp connect is successful), h2loadrunner will re-establish connection to it to reach load balance; false: h2loadrunner will not monitor the host disconnected, and leave the load unbalanced; note: it is not always positive to have this set to true, as it may cause connection to flip-flop when the host itself is unstable",
"default": false,
"type":"boolean"
},
"threads":
{
"description":"Number of threads. Each thread can run multiple connections (see clients field). Recommendation: thead number matches number of cores",
"default": 1,
"type":"integer"
},
"clients":
{
"description":"Total number of concurrent clients(connections) to be established to host(s) under test; different connections are running in parallel mode even they are handled by same thread (see threads field). If working together with rate field, this field specifies the total number of connections to be made. This field must have a value no less than threads field.",
"default": 1,
"type":"integer"
},
"duration":
{
"description":"Specifies the duration (in second) for timing-based benchmarking.",
"default": 60,
"type":"number"
},
"total-requests":
{
"description":"Number of requests across all clients. This field is ignored if duration field has a positive value, and this field must have a positive value if duration field is blank",
"default": 1,
"type":"integer"
},
"warm-up-time":
{
"description":"Specifies the time period (in second) before starting the actual measurements, in case of timing-based benchmarking. Needs non-zero value in duration field for warm-up-time field to work.",
"type":"number"
},
"max-concurrent-streams":
{
"description":"each http2 connection can have multiple concurrent streams running in parallel, this field specifies the max concurrent streams for each connection; this field is ignored for http 1.x test",
"default": 32,
"type":"integer"
},
"request-per-second":
{
"description":"Specifies request per second for each client(connection), so the total number of requests per second would be request-per-second * clients. If no value is given in this field, it will try to send as many as possible requests for each client(connection)",
"type":"number"
},
"request-per-second-feed-file":
{
"description":"If given, h2loadrunner will monitor this file; if the file is changed, h2loadrunner will read the first line, and try to interpret it as a number as described in request-per-second field, and if successful, request-per-second is updated with the number dynamically",
"type":"string"
},
"rate":
{
"description":"Specifies a fixed rate at which connections are created. If given, it must be a positive integer, representing the number of connections to be made per rate-period. The maximum number of connections to be made is given in clients field. This rate will be distributed among threads as evenly as possible. For example, with thread=2 and rate=4, each thread gets 2 connections per rate-period, until total number of connections specified in clients field is reached. When the rate is 0, the program will run as it normally does, creating connections at whatever variable rate it wants.",
"default": 0,
"type":"integer"
},
"rate-period":
{
"description":"Specifies the time period between connection creating connections. The period must be a positive number, representing the length of the period in time. This option is ignored if the rate option is not used.",
"default": 1,
"type":"number"
},
"stream-timeout":
{
"description":"Specifies the maximum time (ms) that h2loadrunner would wait for response before resetting a stream. This field is not applicable for http 1.x test",
"default": 5000,
"type":"integer"
},
"ciphers":
{
"description":"Set allowed cipher list. The format of the string is described in OpenSSL ciphers(1)",
"type":"string",
"default":"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
},
"caCert":
{
"description":"The path to a file whose content is the CA certificate in PEM format. This is used to verify the server certificate",
"type":"string"
},
"cert":
{
"description":"The path to a file whose content is the certificate in PEM format. This is used in mTLS where server requires peer/client certificate",
"type":"string"
},
"privateKey":
{
"description":"The full path to a file whose content is the private key in PEM format. This is used by mTLS where server requires peer certificate, thus the private key is also needed",
"type":"string"
},
"certVerificationMode":
{
"description": "0: do not do certificate validation; 1: fail if peer certificate does not pass validation",
"default": 0,
"type":"integer"
},
"max-tls-version":
{
"type":"string",
"description": "highest allowed TLS version",
"default": "TLSv1.3",
"enum": ["TLSv1.2", "TLSv1.3"]
},
"no-tls-proto":
{
"description":"Specify ALPN identifier of the protocol to be used when accessing http URI without SSL/TLS. Available protocols: h2c and http/1.1",
"type":"string",
"default":"h2c"
},
"connection-active-timeout":
{
"description":"Specifies the maximum time (ms) that h2loadrunner is willing to keep a connection open, regardless of the activity on said connection. If given, it must be a positive integer, specifying the amount of time to wait. When no timeout value is set (either active or inactive), the tool will keep a connection open indefinitely, waiting for a response.",
"type":"number"
},
"connection-inactivity-timeout":
{
"description":"Specifies the amount of time that h2loadrunner is willing to wait to see activity on a given connection. If given, it must be a positive integer, specifying the amount of time to wait. When no timeout value is set (either active or inactive), the tool will keep a connection open indefinitely, waiting for a response.",
"type":"number"
},
"interval-between-ping-frames":
{
"description":"h2loadrunner can send ping frame to peer host to prevent the connection going idle, as a long idle connection might be taken down; this field specifies the max interval (in seconds) between 2 ping frames; if the connection comes out of idle state in less than this interval, next ping frame will not be sent; 0: h2loadrunner will not send ping frames even the connection is idle for long; note: this field is not applicable for http1.x connections",
"default": 0,
"type":"number"
},
"npn-list":
{
"description":"Comma delimited list of ALPN protocol identifier sorted in the order of preference. That means most desirable protocol comes first. This is used in both ALPN and NPN. The parameter must be delimited by a single comma only and any white spaces are treated as a part of protocol string.",
"type":"string",
"default":"h2,h2-16,h2-14,http/1.1"
},
"header-table-size":
{
"description":"Specify decoder header table size.",
"default": 4096,
"type":"integer"
},
"encoder-header-table-size":
{
"description":"Specify encoder header table size. The decoder (server) specifies the maximum dynamic table size it accepts. Then the negotiated dynamic table size is the minimum of this option value and the value which server specified.",
"default": 4096,
"type":"integer"
},
"log-file":
{
"description":"Write per-request brief information to a file with name specified here. columns: start time as microseconds since epoch; HTTP status code; microseconds until end of response. Note: this is not the file to print statistics, and this per-request log may slow down the performance of h2loadrunner",
"type":"string"
},
"failed-request-log-file":
{
"description":"Path to a file; if this is given, h2loadrunner will dump failed request/response details to this file",
"type":"string"
},
"statistics-interval":
{
"description":"This field specifies a repeated timer in seconds; h2loadrunner will print the statistics to stdout or to statistics-file, in Comma-separated values (CSV) format upon each timer expiry",
"default": 5,
"type":"integer"
},
"statistics-file":
{
"description":"Path to a file to write statistics periodically as instructed by statistics-interval. If no file is given here, statistics would be written to stdout",
"type":"string"
},
"builtin-server-listening-port":
{
"description":"h2loadrunner has a builtin http/1.1 server, which would handle incoming request from an http client like curl or a browser, to /stat to get the latest statistics report, and to /config to update configuration options; currently, the only supported configuration option update is rps, e.g., /config?rps=100 will update rps to 100",
"default": 8888,
"type":"integer"
},
"window-bits":
{
"description":"Sets the stream level initial window size to (2^window-bits)-1",
"default": 30,
"type":"integer"
},
"connection-window-bits":
{
"description":"Sets the connection level initial window size to (2^connection-window-bits)-1",
"default": 30,
"type":"integer"
},
"socket-receive-buffer-size":{
"description":"socket receive buffer size in bytes; default: 4M",
"default": 4194304,
"type":"integer"
},
"socket-send-buffer-size":{
"description":"socket send buffer size in bytes; default: 4M",
"default": 4194304,
"type":"integer"
},
"Scenarios":
{
"description":"Array of scenarios, each scenario has a name, a weight, and a list of requests to be executed",
"type":"array",
"minItems":1,
"items":
{
"description":"A scenario is a list of requests to be executed sequentially for each user; different users of the same scenario can be executed in parallel however, even in the same connection.",
"type":"object",
"properties":
{
"name":
{
"description":"name of the scenario, use for statistics output, max length: 24",
"type":"string",
"maxLength": 24
},
"weight":
{
"description":"weight of this scenario among all scenarios; the chance for this scenario to be schedule to run is: weight / total weight of all scenarios",
"default": 100,
"minimum": 0,
"maximum": 65535,
"type":"integer"
},
"interval-to-wait-before-start":
{
"description":"interval (in milliseconds) to wait before this scenario can be scheduled to run; before this interval is over, the weight of this scenario is considered zero; granularity: 100ms",
"default": 0,
"type":"integer"
},
"user-id-variable-in-path-and-data":
{
"description":"Deprecated, use range-based-variables instead. specifies the variable name in uri path and payload, which is considered as a user id, and is to be replaced with an actual value specified by next fields.",
"type":"string"
},
"user-id-list-file":
{
"description":"Deprecated, check two-dimensional-variables instead. Path of a CSV file; Suppose this CSV file has M rows and N columns, then each row (except the first row which is column name) represents a list of identities for one user. So, this file will represent M - 1 users, with each user associated with N identities, and these N identities are for the N requests defined in this scenario respectively. It is acceptable that, there are N requests defined, while only 1 column is present in this file, then for each user, all the N requests will share the same identity from this single column. Note: if user-id-range-slicing is enabled, and the number of users (M - 1) from this file is less than the number of clients, the test cannot be done, as some client would have not even a single user. When user-id-list-file has a value, user-id-range-start/end would be ignored",
"type":"string"
},
"user-id-range-start":
{
"description":"Deprecated, use range-based-variables instead. specify variable user id range start; for example, user-id-range-start = 0, user-id-range-end = 1000, then the actual user id would be 0000, 0001, 0002, ... 0999",
"type":"integer"
},
"user-id-range-end":
{
"description":"Deprecated, use range-based-variables instead. specify variable user id range end; actual range does not include the end, which is: [user-id-range-start, user-id-range-end)",
"type":"integer"
},
"user-id-range-slicing":
{
"description": "true: Slice the user-id range, each client get a sub range; e.g.: full range 1-1000, with 10 clients, each client gets a sub range of 100 (1-100, 101-200...); if user-id-list-file is given, the full list of the user id list from that file will be sliced up, and each client will take a sub list. false: each client gets a full range",
"default": true,
"type":"boolean"
},
"run-requests-in-parallel":
{
"description": "true: all the requests of this scenario will be run in parallel, obvious, the request uri typeOfAction cannot be fromResponseHeader or fromJsonPointer in this case; false: the requests of this scenario will be run one after another in the listed order",
"default": false,
"type":"boolean"
},
"user-variables-input-file":
{
"description":"path of a UTF-8 CSV file; the first row must be the list of column names, and each colume name is interpreted as a variable name; the value of this variable is given from the second row and after, with each row representing a specific user; suppose the CSV files has M columns and N rows, then it represents N-1 users: each row represents the M variable values of a single user; each variable value can be referred to in user message definition by wrapping the variable name with ${}, where variable name is given in the corresponding column at the first row",
"type":"string"
},
"range-based-variables":
{
"description":"Array of range based variables, each has a name, range start and range end; the name can be referred to in request uri, payload, and header definition, wrapper with ${}, like /some-path/${var_name}, where ${var_name} is to be substituted by an actual value within range start and range end",
"type":"array",
"minItems":0,
"items":
{
"type":"object",
"properties":
{
"variable-name":
{
"description":"Specifies the variable name",
"type":"string"
},
"variable-range-start":
{
"description":"Specify variable range start; for example, variable-range-start = 0, variable-range-end = 1000, then the actual user id would be 0000, 0001, 0002, ... 0999",
"type":"integer"
},
"variable-range-end":
{
"description":"Specify variable range end; actual range does not include the end, which is: [variable-range-start, variable-range-end)",
"type":"integer"
}
}
}
},
"two-dimensional-variables":
{
"description":"Array of csv based variables, each variable has a name, and path to a csv file; the name can be referred to in request uri, payload, and header definition, wrapper with ${}, like /some-path/${var_name}, where ${var_name} is to be substituted by an actual value from the csv file",
"type":"array",
"minItems":0,
"items":
{
"type":"object",
"properties":
{
"variable-name":
{
"description":"Specifies the variable name",
"type":"string"
},
"file-name":
{
"description":"path of a csv file; Suppose this csv file has M rows and N columns, then each row (except the first row which is column name and is ignored) represents a list of identities for one user. So, this file will represent M - 1 users, with each user associated with N identities, and these N identities are for the N requests defined in this scenario respectively. Note: if user-id-range-slicing is enabled, and the number of users (M - 1) from this file is less than the number of clients, the test cannot be done, as some client would have not even a single user.",
"type":"string"
}
}
}
},
"Requests":
{
"description":"Array of requests, each request has URI, method, optional payload, optional addtional headers, and optionally an lua script for advanced users to customize the request",
"type":"array",
"minItems":1,
"items":
{
"type": "object",
"properties":
{
"uri":
{
"description": "This could be a full URI with schema, authority, path, etc., or, it can be path only, in the latter case, the global schema, host, port fields would be used to construct the full URI",
"type":"object",
"properties":
{
"typeOfAction":
{
"type":"string",
"description": "Specifies how to generate the URI. input: direct input into input field, and the input can include variables wrapped with ${}; sameWithLastOne: same URI with last request; fromResponseHeader: extract the URI for this request from a specific header (name specified in input field) of last response; fromLuaScript: provide URI by lua script (see field luaScript); fromXpath: Search XML body of last response for the XPATH value given in input field (to be implemented); fromJsonPointer: Search Json body of last response body for the Json pointer value given in input field (to be implemented)",
"enum": ["input", "sameWithLastOne", "fromResponseHeader", "fromLuaScript", "fromXPath", "fromJsonPointer"]
},
"input":
{
"description": "input needed to execute the typeOfAction above",
"type":"string"
}
}
},
"clear-old-cookies":
{
"description": "clear cookies before executing this request: cookies received prior to this request, will be cleared, and will not be included in Cookie header of this request and after; Cookies header (if any) in additonalHeaders below for this request, will still be sent (but will not be passed on to next request)",
"default": false,
"type":"boolean"
},
"method":
{
"description": "method of the HTTP(2) request",
"default": "GET",
"type":"string"
},
"payload":
{
"description": "http message content, or a filename containing the actual content",
"type":"string"
},
"additonalHeaders":
{
"description": "additional headers to include in this request. Valid format for each header: pair of strings with : in the middle; for example, user-agent: h2loadrunner",
"type": "array",
"items":
{
"type": "string"
}
},
"luaScript":
{
"type":"string",
"description": "lua script (or a filename containing the actual script). The script can be used to customize the request, and to validate the response; to customized the request, a function named make_request should be present, handling 4 arguments: response_headers, response_payload, request_headers_to_send, request_payload_to_send; returning request_headers_to_send and request_payload_to_send. h2loadrunner passes the response headers and payload of last request within this scenarios sequence, and the request headers (path, method, additional headers) and payload specified here, to this lua function, which can update the request headers and request payload, and h2loadrunner will use the updated headers and payload for the request. Example make_request: function make_request(response_header, response_payload, request_headers_to_send, request_payload_to_send) return request_headers_to_send, request_payload_to_send end To validate response, a function named validate_response should be present, handling 2 argument, response_header and response_payload, returning true or false. h2loadrunner passes the response headers and payload to function validate_response, and validate_response can do whatever check to decide whether the response is a success or a failure and return the result accordingly. Note: if validate_response function is provided, the result from it will override the result from expected-status-code and response-match"
},
"expected-status-code":
{
"description":"the expected http status code for this request; if the returned status code matches the one specified here, this request is considered successful in statistics report; if nothing or 0 is specified here, 2xx status codes (i.e., 200, 201, 204, etc.) are all considered successful",
"default": 0,
"type":"integer"
},
"response-match":{
"description": "A list of matching rules of both headers and payload; if provisioned, the received response is validated with the matching rules, and the result will override that from expected-status-code; if all matching rules given below are successful, the response is considered successful; otherwise, this response is considered as failed",
"type":"object",
"properties":{
"headers":{
"description": "Array of matching rules to be executed against the response headers",
"type":"array",
"minItems":0,
"items": {
"type": "object",
"description": "One matching rule to be executed against one response header",
"properties":{
"header-name":{
"description": "This field specifies the name of a received header; the value of this header is to be picked up to run the match",
"default": ":status",
"type":"string"
},
"matchType":{
"type":"string",
"description": "Type of match action",
"default": "EqualsTo",
"enum": ["EqualsTo", "StartsWith", "EndsWith", "Contains", "RegexMatch"]
},
"input":{
"description": "Content used to run the matchType above against the received header value; i.e., received header value should either equal to or start with or end with or contain the content specified in this field; if RegexMatch is chosen, it means this input field is a regular expression of ECMAScript flavor, and it should match the entire target character sequence, i.e., the header value",
"default": "200",
"type":"string"
}
}
}
},
"payload": {
"description": "Array of matching rules to be executed against the received Json payload",
"type":"array",
"minItems":0,
"items": {
"type": "object",
"description": "One matching rule to be executed against the received Json payload",
"properties":{
"JsonPointer": {
"description": "A Json pointer to locate a value within the received Json payload",
"type":"string"
},
"matchType": {
"type":"string",
"description": "Type of match action",
"enum": ["EqualsTo", "StartsWith", "EndsWith", "Contains", "RegexMatch"]
},
"input": {
"description": "Content used to execute the matchType above against the value specified by the Json pointer above; the value specified by the Json pointer above should either equal to or start with or end with or contain the content specified in this field; if RegexMatch is chosen, it means this input field is a regular expression of ECMAScript flavor, and it should match the entire target character sequence, i.e., the value specified by the Json pointer",
"type":"string"
}
}
}
}
}
},
"value-pickers":
{
"description": "This is the actions to run when the response is received; it is using a regular expression of ECMAScript flavor to pick up a value, from a specific header, or from a value in the payload specified by a Json pointer, and then save the value to a variable whose name is given in save-to-variable; the stored value can be accessed later by wrapping the name of the variable with ${}, for example, pick up a value from the response header here, and store it to a variable named user_id, and then refer to this variable in a later request of the same scenario in this way: some_api_path/${user_id}, and ${user_id} would be replaced by the actual value stored here",
"type": "array",
"items": {
"type": "object",
"description": "One value-picker",
"properties":{
"where-to-pickup-from": {
"description": "where to pick up the value from: from request header, request payload, response header, response payload",
"type":"string",
"enum": ["Request-Header", "Response-Header", "Json-Pointer-In-Request-Payload", "Json-Pointer-In-Response-Payload"]
},
"source": {
"type":"string",
"description": "A header name, or a Json pointer, depending on what is given in where-to-pickup-from"
},
"regexp": {
"description": "A regular expression of ECMAScript flavor to extract value from the source above",
"default": ".*",
"type":"string"
},
"save-to-variable": {
"description": "A name of the varible into what the extracted value is saved to, and this name could be refered to in subsequent requests of the same user id, to fetch the value by wrapping the name with ${}",
"type":"string"
}
}
}
},
"delay-before-executing-next":
{
"description":"milliseconds to delay before executing the next request within the same scenario; granularity: 10ms, i.e., setting 115ms delay would cause an actual delay of 120ms",
"default": 0,
"type":"integer"
}
},
"required":[
"uri",
"method"
]
}
}
},
"required":[
"name",
"Requests"
]
}
}
},
"required":
[
"schema",
"host",
"Scenarios"
]
}