@@ -19,14 +19,20 @@ export interface LoadtestOptions extends ProcOptions {
19
19
calmdown : number ;
20
20
/** How many times to run the loadtests? */
21
21
runs : number ;
22
- /** The snapshotting window of the GraphQL server memory in milliseconds. */
22
+ /** The snapshotting window of the server memory in milliseconds. */
23
23
memorySnapshotWindow : number ;
24
- /** The GraphQL server on which the loadtest is running. */
24
+ /** The server on which the loadtest is running. */
25
25
server : Server ;
26
26
/**
27
27
* The GraphQL query to execute for the loadtest.
28
+ * Either `query` or `pathname` must be provided.
28
29
*/
29
- query : string ;
30
+ query ?: string ;
31
+ /**
32
+ * The HTTP pathname to request for the loadtest.
33
+ * Either `query` or `pathname` must be provided.
34
+ */
35
+ pathname ?: string ;
30
36
/**
31
37
* Whether to take heap snapshots on the end of the `idle` phase and then at the end
32
38
* of the `calmdown` {@link LoadtestPhase phase} in each of the {@link runs}.
@@ -104,6 +110,7 @@ export async function loadtest(opts: LoadtestOptions): Promise<{
104
110
memorySnapshotWindow,
105
111
server,
106
112
query,
113
+ pathname,
107
114
takeHeapSnapshots,
108
115
performHeapSampling,
109
116
allowFailingRequests,
@@ -120,36 +127,58 @@ export async function loadtest(opts: LoadtestOptions): Promise<{
120
127
throw new Error ( `At least one run is necessary, got "${ runs } "` ) ;
121
128
}
122
129
130
+ if ( ! query && ! pathname ) {
131
+ throw new Error ( 'Either "query" or "pathname" must be provided' ) ;
132
+ }
133
+
134
+ if ( query && pathname ) {
135
+ throw new Error ( 'Cannot provide both "query" and "pathname"' ) ;
136
+ }
137
+
123
138
const startTime = new Date ( ) ;
124
139
125
140
// we create a random id to make sure the heapsnapshot files are unique and easily distinguishable in the filesystem
126
141
// when running multiple loadtests in parallel. see e2e/opentelemetry memtest as an example
127
142
const id = Math . random ( ) . toString ( 36 ) . slice ( 2 , 6 ) ;
128
143
129
- // make sure the query works before starting the loadtests
130
- // the request here matches the request done in loadtest-script.ts
131
- const res = await fetch (
132
- `${ server . protocol } ://localhost:${ server . port } /graphql` ,
133
- {
134
- method : 'POST' ,
135
- headers : {
136
- 'content-type' : 'application/json' ,
144
+ // make sure the endpoint works before starting the loadtests
145
+ // the request here matches the request done in loadtest-script.ts or http-loadtest-script.ts
146
+ if ( query ) {
147
+ const res = await fetch (
148
+ `${ server . protocol } ://localhost:${ server . port } /graphql` ,
149
+ {
150
+ method : 'POST' ,
151
+ headers : {
152
+ 'content-type' : 'application/json' ,
153
+ } ,
154
+ body : JSON . stringify ( { query } ) ,
137
155
} ,
138
- body : JSON . stringify ( { query } ) ,
139
- } ,
140
- ) ;
141
- const text = await res . text ( ) ;
142
- if ( ! res . ok ) {
143
- const err = new Error (
144
- `Status is not 200, got status ${ res . status } ${ res . statusText } and body:\n${ text } ` ,
145
156
) ;
146
- err . name = 'ResponseError' ;
147
- throw err ;
148
- }
149
- if ( ! text . includes ( '"data":{' ) ) {
150
- const err = new Error ( `Body does not contain "data":\n${ text } ` ) ;
151
- err . name = 'ResponseError' ;
152
- throw err ;
157
+ const text = await res . text ( ) ;
158
+ if ( ! res . ok ) {
159
+ const err = new Error (
160
+ `Status is not 200, got status ${ res . status } ${ res . statusText } and body:\n${ text } ` ,
161
+ ) ;
162
+ err . name = 'ResponseError' ;
163
+ throw err ;
164
+ }
165
+ if ( ! text . includes ( '"data":{' ) ) {
166
+ const err = new Error ( `Body does not contain "data":\n${ text } ` ) ;
167
+ err . name = 'ResponseError' ;
168
+ throw err ;
169
+ }
170
+ } else if ( pathname ) {
171
+ const res = await fetch (
172
+ `${ server . protocol } ://localhost:${ server . port } ${ pathname } ` ,
173
+ ) ;
174
+ if ( ! res . ok ) {
175
+ const text = await res . text ( ) ;
176
+ const err = new Error (
177
+ `Status is not 200, got status ${ res . status } ${ res . statusText } and body:\n${ text } ` ,
178
+ ) ;
179
+ err . name = 'ResponseError' ;
180
+ throw err ;
181
+ }
153
182
}
154
183
155
184
const ctrl = new AbortController ( ) ;
@@ -244,9 +273,17 @@ export async function loadtest(opts: LoadtestOptions): Promise<{
244
273
'run' ,
245
274
`--vus=${ vus } ` ,
246
275
`--duration=${ duration } ms` ,
247
- `--env=URL=${ server . protocol } ://localhost:${ server . port } /graphql` ,
248
- `--env=QUERY=${ query } ` ,
249
- path . join ( __dirname , 'loadtest-script.ts' ) ,
276
+ // graphql
277
+ query &&
278
+ `--env=URL=${ server . protocol } ://localhost:${ server . port } /graphql` ,
279
+ query && `--env=QUERY=${ query } ` ,
280
+ // pathname
281
+ pathname &&
282
+ `--env=URL=${ server . protocol } ://localhost:${ server . port } ${ pathname } ` ,
283
+ path . join (
284
+ __dirname ,
285
+ query ? 'graphql-loadtest-script.ts' : 'pathname-loadtest-script.ts' ,
286
+ ) ,
250
287
) ;
251
288
await Promise . race ( [ waitForExit , serverThrowOnExit , memorySnapshotting ] ) ;
252
289
0 commit comments