@api-client/core 0.5.26 → 0.6.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 (95) hide show
  1. package/build/browser.d.ts +2 -1
  2. package/build/browser.js.map +1 -1
  3. package/build/index.d.ts +2 -1
  4. package/build/index.js.map +1 -1
  5. package/build/src/events/EventTypes.d.ts +16 -0
  6. package/build/src/events/EventTypes.js +2 -0
  7. package/build/src/events/EventTypes.js.map +1 -1
  8. package/build/src/events/Events.d.ts +16 -0
  9. package/build/src/events/Events.js +2 -0
  10. package/build/src/events/Events.js.map +1 -1
  11. package/build/src/events/transport/TransportEventTypes.d.ts +31 -0
  12. package/build/src/events/transport/TransportEventTypes.js +36 -0
  13. package/build/src/events/transport/TransportEventTypes.js.map +1 -0
  14. package/build/src/events/transport/TransportEvents.d.ts +77 -0
  15. package/build/src/events/transport/TransportEvents.js +91 -0
  16. package/build/src/events/transport/TransportEvents.js.map +1 -0
  17. package/build/src/mocking/LegacyInterfaces.d.ts +4 -4
  18. package/build/src/mocking/LegacyMock.js +1 -0
  19. package/build/src/mocking/LegacyMock.js.map +1 -1
  20. package/build/src/mocking/ProjectMock.d.ts +2 -2
  21. package/build/src/mocking/ProjectMock.js.map +1 -1
  22. package/build/src/mocking/legacy/Http.d.ts +5 -4
  23. package/build/src/mocking/legacy/Http.js +8 -6
  24. package/build/src/mocking/legacy/Http.js.map +1 -1
  25. package/build/src/mocking/legacy/HttpResponse.d.ts +1 -1
  26. package/build/src/mocking/legacy/HttpResponse.js +1 -1
  27. package/build/src/mocking/legacy/HttpResponse.js.map +1 -1
  28. package/build/src/mocking/lib/History.d.ts +5 -5
  29. package/build/src/mocking/lib/History.js +4 -4
  30. package/build/src/mocking/lib/History.js.map +1 -1
  31. package/build/src/mocking/lib/Request.d.ts +14 -7
  32. package/build/src/mocking/lib/Request.js +4 -4
  33. package/build/src/mocking/lib/Request.js.map +1 -1
  34. package/build/src/mocking/lib/Response.d.ts +9 -11
  35. package/build/src/mocking/lib/Response.js +25 -14
  36. package/build/src/mocking/lib/Response.js.map +1 -1
  37. package/build/src/mocking/lib/Url.d.ts +2 -2
  38. package/build/src/mocking/lib/Url.js.map +1 -1
  39. package/build/src/mocking/lib/User.d.ts +2 -2
  40. package/build/src/mocking/lib/User.js +0 -1
  41. package/build/src/mocking/lib/User.js.map +1 -1
  42. package/build/src/models/RequestConfig.d.ts +10 -0
  43. package/build/src/models/RequestConfig.js +13 -1
  44. package/build/src/models/RequestConfig.js.map +1 -1
  45. package/build/src/runtime/http-engine/CoreEngine.js +1 -1
  46. package/build/src/runtime/http-engine/CoreEngine.js.map +1 -1
  47. package/build/src/runtime/http-engine/HttpEngine.d.ts +12 -0
  48. package/build/src/runtime/http-engine/HttpEngine.js +34 -0
  49. package/build/src/runtime/http-engine/HttpEngine.js.map +1 -1
  50. package/build/src/runtime/node/InteropInterfaces.d.ts +5 -0
  51. package/build/src/runtime/node/ProjectParallelRunner.d.ts +20 -0
  52. package/build/src/runtime/node/ProjectParallelRunner.js +69 -1
  53. package/build/src/runtime/node/ProjectParallelRunner.js.map +1 -1
  54. package/build/src/runtime/node/ProjectRequestRunner.d.ts +8 -0
  55. package/build/src/runtime/node/ProjectRequestRunner.js +19 -0
  56. package/build/src/runtime/node/ProjectRequestRunner.js.map +1 -1
  57. package/build/src/runtime/node/ProjectRunner.d.ts +25 -0
  58. package/build/src/runtime/node/ProjectRunner.js +55 -0
  59. package/build/src/runtime/node/ProjectRunner.js.map +1 -1
  60. package/build/src/runtime/node/ProjectRunnerWorker.js +3 -0
  61. package/build/src/runtime/node/ProjectRunnerWorker.js.map +1 -1
  62. package/build/src/runtime/node/ProjectSerialRunner.js +3 -0
  63. package/build/src/runtime/node/ProjectSerialRunner.js.map +1 -1
  64. package/build/src/runtime/node/RequestFactory.d.ts +6 -0
  65. package/build/src/runtime/node/RequestFactory.js +10 -1
  66. package/build/src/runtime/node/RequestFactory.js.map +1 -1
  67. package/build/src/runtime/node/enums.d.ts +8 -0
  68. package/build/src/runtime/node/enums.js +10 -0
  69. package/build/src/runtime/node/enums.js.map +1 -0
  70. package/package.json +5 -5
  71. package/src/events/EventTypes.ts +2 -0
  72. package/src/events/Events.ts +2 -0
  73. package/src/events/transport/TransportEventTypes.ts +37 -0
  74. package/src/events/transport/TransportEvents.ts +116 -0
  75. package/src/mocking/LegacyInterfaces.ts +4 -4
  76. package/src/mocking/LegacyMock.ts +1 -0
  77. package/src/mocking/ProjectMock.ts +2 -2
  78. package/src/mocking/legacy/Http.ts +12 -9
  79. package/src/mocking/legacy/HttpResponse.ts +3 -3
  80. package/src/mocking/lib/History.ts +7 -7
  81. package/src/mocking/lib/Request.ts +18 -10
  82. package/src/mocking/lib/Response.ts +31 -22
  83. package/src/mocking/lib/Url.ts +2 -2
  84. package/src/mocking/lib/User.ts +2 -3
  85. package/src/models/RequestConfig.ts +19 -1
  86. package/src/runtime/http-engine/CoreEngine.ts +1 -1
  87. package/src/runtime/http-engine/HttpEngine.ts +39 -0
  88. package/src/runtime/node/InteropInterfaces.ts +6 -0
  89. package/src/runtime/node/ProjectParallelRunner.ts +75 -1
  90. package/src/runtime/node/ProjectRequestRunner.ts +22 -0
  91. package/src/runtime/node/ProjectRunner.ts +63 -0
  92. package/src/runtime/node/ProjectRunnerWorker.ts +3 -0
  93. package/src/runtime/node/ProjectSerialRunner.ts +3 -2
  94. package/src/runtime/node/RequestFactory.ts +11 -1
  95. package/src/runtime/node/enums.ts +8 -0
@@ -1,15 +1,14 @@
1
- import { Http as Base, Types, Lorem, Time, HttpRequestInit } from '@pawel-up/data-mock';
2
- import { randomValue } from '@pawel-up/data-mock/build/src/lib/Http.js';
1
+ import { Http as Base, Types, Lorem, Time, IHttpRequestInit, Random } from '@pawel-up/data-mock';
3
2
  import { ArcDataMockInit } from '../LegacyInterfaces.js';
4
3
  import { HttpResponse } from './HttpResponse.js';
5
4
  import { ARCHistoryRequest, ARCSavedRequest, TransportRequest } from '../../models/legacy/request/ArcRequest.js';
6
5
  import { ARCProject } from '../../models/legacy/models/ArcLegacyProject.js';
7
6
 
8
- export interface RequestHistoryInit extends HttpRequestInit {
7
+ export interface RequestHistoryInit extends IHttpRequestInit {
9
8
  noId?: boolean;
10
9
  }
11
10
 
12
- export interface RequestSavedInit extends HttpRequestInit {
11
+ export interface RequestSavedInit extends IHttpRequestInit {
13
12
  forceDescription?: boolean;
14
13
  noDescription?: boolean;
15
14
  project?: string;
@@ -33,7 +32,7 @@ export declare interface GenerateSavedResult {
33
32
  requests: ARCSavedRequest[];
34
33
  }
35
34
 
36
- export interface TransportRequestInit extends HttpRequestInit {
35
+ export interface TransportRequestInit extends IHttpRequestInit {
37
36
  noHttpMessage?: boolean;
38
37
  }
39
38
 
@@ -41,9 +40,12 @@ export class Http extends Base {
41
40
  LAST_TIME: number;
42
41
  types: Types;
43
42
  lorem: Lorem;
43
+ // @ts-ignore
44
44
  response: HttpResponse;
45
45
  time: Time;
46
46
 
47
+ protected _random: Random;
48
+
47
49
  constructor(init: ArcDataMockInit={}) {
48
50
  super(init);
49
51
  this.LAST_TIME = Date.now();
@@ -51,10 +53,11 @@ export class Http extends Base {
51
53
  this.lorem = new Lorem(init);
52
54
  this.response = new HttpResponse(init);
53
55
  this.time = new Time(init);
56
+ this._random = new Random(init.seed);
54
57
  }
55
58
 
56
59
  history(opts: RequestHistoryInit={}): ARCHistoryRequest {
57
- const base = this.request(opts);
60
+ const base = this.request.request(opts);
58
61
  this.LAST_TIME -= this.types.datetime().getTime();
59
62
  const midnight = this.time.midnight(this.LAST_TIME);
60
63
 
@@ -72,7 +75,7 @@ export class Http extends Base {
72
75
  }
73
76
 
74
77
  saved(opts: RequestSavedInit={}): ARCSavedRequest {
75
- const base = this.request(opts);
78
+ const base = this.request.request(opts);
76
79
  const time = this.types.datetime().getTime();
77
80
  const requestName = this.lorem.words(2);
78
81
  const description = this.description(opts);
@@ -165,7 +168,7 @@ export class Http extends Base {
165
168
  allow = this.types.boolean();
166
169
  }
167
170
  if (allow) {
168
- return this[randomValue].pickOne(opts.projects);
171
+ return this._random.pickOne(opts.projects);
169
172
  }
170
173
  return undefined;
171
174
  }
@@ -214,7 +217,7 @@ export class Http extends Base {
214
217
  * @returns The transport request object
215
218
  */
216
219
  transportRequest(opts: TransportRequestInit={}): TransportRequest {
217
- const base = this.request(opts);
220
+ const base = this.request.request(opts);
218
221
  const request: TransportRequest = {
219
222
  ...base,
220
223
  startTime: Date.now() - 1000,
@@ -1,4 +1,4 @@
1
- import { HttpResponse as Base, headersValue, payloadValue, typesValue, loremValue } from '@pawel-up/data-mock/build/src/lib/http/HttpResponse.js';
1
+ import Base, { headersValue, payloadValue, typesValue, loremValue } from '@pawel-up/data-mock/build/src/lib/http/Response.js';
2
2
  import { Har, DataMockLocale } from '@pawel-up/data-mock';
3
3
  import { ArcDataMockInit, HttpResponseArcInit, HttpResponseRedirectInit } from '../LegacyInterfaces.js';
4
4
  import { ResponseRedirect, Response, ErrorResponse } from '../../models/legacy/request/ArcResponse.js';
@@ -36,7 +36,7 @@ export class HttpResponse extends Base {
36
36
  const url = this[headersValue].link();
37
37
  headers += `\nlocation: ${url}`;
38
38
  const { code, status } = this.redirectStatus(init);
39
- const body = init.body ? this[payloadValue].payload(ct) : undefined;
39
+ const body = init.body ? this[payloadValue].payload(ct as string) : undefined;
40
40
  const startTime = this[typesValue].datetime().getTime();
41
41
  const duration = this[typesValue].number({ min: 10, max: 4000 });
42
42
  const result: ResponseRedirect = {
@@ -60,7 +60,7 @@ export class HttpResponse extends Base {
60
60
 
61
61
  arcResponse(init: HttpResponseArcInit = {}): Response {
62
62
  const ct = init.noBody ? undefined : this[headersValue].contentType();
63
- const body = init.noBody ? undefined : this[payloadValue].payload(ct);
63
+ const body = init.noBody ? undefined : this[payloadValue].payload(ct as string);
64
64
  const headers = this[headersValue].headers('response', { mime: ct });
65
65
  const statusGroup = init.statusGroup ? init.statusGroup : this[typesValue].number({ min: 2, max: 5 });
66
66
  const sCode = this[typesValue].number({ min: 0, max: 99 }).toString();
@@ -1,4 +1,4 @@
1
- import { Internet, Types, DataMockInit, Person, Random, TypeDateTimeInit } from '@pawel-up/data-mock';
1
+ import { Internet, Types, IDataMockInit, Person, Random, ITypeDateTimeInit } from '@pawel-up/data-mock';
2
2
  // import { randomValue } from '@pawel-up/data-mock/src/lib/Http.js';
3
3
  import { IHttpHistory, Kind as HttpHistoryKind } from '../../models/HttpHistory.js';
4
4
  import { Request, IRequestLogInit } from './Request.js';
@@ -32,7 +32,7 @@ export interface IHttpHistoryInit {
32
32
  /**
33
33
  * The created time init options.
34
34
  */
35
- created?: TypeDateTimeInit;
35
+ created?: ITypeDateTimeInit;
36
36
  }
37
37
 
38
38
  export interface IHttpHistoryListInit extends IHttpHistoryInit {
@@ -70,7 +70,7 @@ export class History {
70
70
  random: Random;
71
71
  request: Request;
72
72
 
73
- constructor(init: DataMockInit={}) {
73
+ constructor(init: IDataMockInit={}) {
74
74
  this.person = new Person(init);
75
75
  this.types = new Types(init.seed);
76
76
  this.internet = new Internet(init);
@@ -78,12 +78,12 @@ export class History {
78
78
  this.request = new Request(init);
79
79
  }
80
80
 
81
- httpHistory(init: IHttpHistoryInit = {}): IHttpHistory {
81
+ async httpHistory(init: IHttpHistoryInit = {}): Promise<IHttpHistory> {
82
82
  const date = this.types.datetime(init.created);
83
83
  const result: IHttpHistory = {
84
84
  kind: HttpHistoryKind,
85
85
  created: date.getTime(),
86
- log: this.request.log(init.log),
86
+ log: await this.request.log(init.log),
87
87
  user: '',
88
88
  }
89
89
  date.setHours(0, 0, 0, 0);
@@ -131,7 +131,7 @@ export class History {
131
131
  return result;
132
132
  }
133
133
 
134
- httpHistoryList(size=25, init: IHttpHistoryListInit = {}): IHttpHistory[] {
134
+ async httpHistoryList(size=25, init: IHttpHistoryListInit = {}): Promise<IHttpHistory[]> {
135
135
  const { usersSize, spacesSize, projectsSize, requestsSize, appsSize } = init;
136
136
  const copy = { ...init };
137
137
  if (usersSize && typeof init.user === 'undefined') {
@@ -172,7 +172,7 @@ export class History {
172
172
 
173
173
  const result: IHttpHistory[] = [];
174
174
  for (let i = 0; i < size; i++) {
175
- result.push(this.httpHistory(copy));
175
+ result.push(await this.httpHistory(copy));
176
176
  }
177
177
  return result;
178
178
  }
@@ -1,4 +1,4 @@
1
- import { Http, Types, Lorem, Time, DataMockInit, HttpRequestInit } from '@pawel-up/data-mock';
1
+ import { Http, Types, Lorem, Time, IDataMockInit, IHttpRequestInit } from '@pawel-up/data-mock';
2
2
  // import { randomValue } from '@pawel-up/data-mock/src/lib/Http.js';
3
3
  import { IHttpRequest, Kind as HttpRequestKind } from '../../models/HttpRequest.js';
4
4
  import { IRequest, Kind as RequestKind } from '../../models/Request.js';
@@ -7,7 +7,7 @@ import { IRequestLog, Kind as RequestLogKind } from '../../models/RequestLog.js'
7
7
  import { IResponseInit, Response } from './Response.js';
8
8
 
9
9
  export interface IRequestLogInit {
10
- request?: HttpRequestInit;
10
+ request?: IHttpRequestInit;
11
11
  response?: IResponseInit;
12
12
  /**
13
13
  * When set it ignores size information
@@ -21,6 +21,14 @@ export interface IRequestLogInit {
21
21
  noRequest?: boolean;
22
22
  }
23
23
 
24
+ export interface IRequestInit extends IResponseInit {
25
+ /**
26
+ * The content type to generate the body for.
27
+ * Has no effect when `noBody` is set.
28
+ */
29
+ contentType?: string;
30
+ }
31
+
24
32
  export class Request {
25
33
  types: Types;
26
34
  lorem: Lorem;
@@ -28,7 +36,7 @@ export class Request {
28
36
  http: Http;
29
37
  response: Response;
30
38
 
31
- constructor(init: DataMockInit={}) {
39
+ constructor(init: IDataMockInit={}) {
32
40
  this.types = new Types(init.seed);
33
41
  this.lorem = new Lorem(init);
34
42
  this.time = new Time(init);
@@ -36,7 +44,7 @@ export class Request {
36
44
  this.response = new Response(init);
37
45
  }
38
46
 
39
- request(init?: HttpRequestInit): IRequest {
47
+ request(init?: IHttpRequestInit): IRequest {
40
48
  return {
41
49
  kind: RequestKind,
42
50
  expects: this.httpRequest(init),
@@ -47,15 +55,15 @@ export class Request {
47
55
  }
48
56
  }
49
57
 
50
- httpRequest(init?: HttpRequestInit): IHttpRequest {
51
- const request = this.http.request(init);
58
+ httpRequest(init?: IHttpRequestInit): IHttpRequest {
59
+ const request = this.http.request.request(init);
52
60
  return {
53
61
  kind: HttpRequestKind,
54
62
  ...request,
55
63
  }
56
64
  }
57
65
 
58
- sentRequest(init?: HttpRequestInit): ISentRequest {
66
+ sentRequest(init?: IHttpRequestInit): ISentRequest {
59
67
  const start = this.time.timestamp();
60
68
  return {
61
69
  startTime: start,
@@ -64,7 +72,7 @@ export class Request {
64
72
  };
65
73
  }
66
74
 
67
- log(init: IRequestLogInit = {}): IRequestLog {
75
+ async log(init: IRequestLogInit = {}): Promise<IRequestLog> {
68
76
  const result: IRequestLog = {
69
77
  kind: RequestLogKind,
70
78
  };
@@ -72,10 +80,10 @@ export class Request {
72
80
  result.request = this.sentRequest(init.request);
73
81
  }
74
82
  if (!init.noResponse) {
75
- result.response = this.response.response(init.response);
83
+ result.response = await this.response.response(init.response);
76
84
  }
77
85
  if (init.redirects) {
78
- result.redirects = this.response.redirects();
86
+ result.redirects = await this.response.redirects();
79
87
  }
80
88
  if (!init.noSize) {
81
89
  result.size = this.response.size();
@@ -1,14 +1,11 @@
1
- import { Http, Har, Types, Lorem, Time, DataMockInit, HttpResponseInit, HarTimingInit, Internet } from '@pawel-up/data-mock';
2
- import { IHttpResponse, Kind as HttpResponseKind } from '../../models/HttpResponse.js';
1
+ import { Http, Har, Types, Lorem, Time, IDataMockInit, IHttpResponseInit, IHarTimingInit, Internet, IHttpPayloadInit } from '@pawel-up/data-mock';
2
+ import { IHttpResponse, HttpResponse, Kind as HttpResponseKind } from '../../models/HttpResponse.js';
3
3
  import { IResponse, Kind as ResponseKind } from '../../models/Response.js';
4
4
  import { IRequestsSize } from '../../models/RequestsSize.js';
5
5
  import { IResponseRedirect, Kind as ResponseRedirectKind } from '../../models/ResponseRedirect.js';
6
+ import { DeserializedPayload } from '../../lib/transformers/PayloadSerializer.js';
6
7
 
7
- export interface IResponseInit extends HttpResponseInit, HarTimingInit {
8
- /**
9
- * When set it does not generate a response payload.
10
- */
11
- noBody?: boolean;
8
+ export interface IResponseInit extends IHttpResponseInit, IHarTimingInit {
12
9
  /**
13
10
  * The first number of the status group. Other 2 are auto generated
14
11
  */
@@ -27,7 +24,7 @@ export class Response {
27
24
  har: Har;
28
25
  internet: Internet;
29
26
 
30
- constructor(init: DataMockInit={}) {
27
+ constructor(init: IDataMockInit={}) {
31
28
  this.types = new Types(init.seed);
32
29
  this.lorem = new Lorem(init);
33
30
  this.time = new Time(init);
@@ -36,10 +33,21 @@ export class Response {
36
33
  this.internet = new Internet(init);
37
34
  }
38
35
 
39
- httpResponse(init: IResponseInit = {}): IHttpResponse {
40
- const ct = init.noBody ? undefined : this.http.headers.contentType();
41
- const body = init.noBody ? undefined : this.http.payload.payload(ct);
42
- const headers = this.http.headers.headers('response', { mime: ct });
36
+ protected _getPayload(mime?: string): DeserializedPayload {
37
+ if (mime) {
38
+ return undefined;
39
+ }
40
+ switch (mime) {
41
+ case 'multipart/form-data': return this.http.formData.form();
42
+ default:
43
+ return this.http.payload.payload(mime as string);
44
+ }
45
+ }
46
+
47
+ async httpResponse(init: IResponseInit = {}): Promise<IHttpResponse> {
48
+ const mime = this.http.headers.contentType(init.payload as IHttpPayloadInit);
49
+ const body = this._getPayload(mime);
50
+ const headers = this.http.headers.headers('response', { mime: mime });
43
51
  const statusGroup = init.statusGroup ? init.statusGroup : this.types.number({ min: 2, max: 5 });
44
52
  const sCode = this.types.number({ min: 0, max: 99 }).toString();
45
53
  const code = Number(`${statusGroup}${sCode.padStart(2, '0')}`);
@@ -50,14 +58,15 @@ export class Response {
50
58
  statusText: status,
51
59
  headers,
52
60
  };
53
- if (!init.noBody) {
54
- result.payload = body;
61
+ const response = new HttpResponse(result);
62
+ if (body) {
63
+ await response.writePayload(body)
55
64
  }
56
- return result;
65
+ return response.toJSON();
57
66
  }
58
67
 
59
- response(init: IResponseInit={}): IResponse {
60
- const base = this.httpResponse(init);
68
+ async response(init: IResponseInit={}): Promise<IResponse> {
69
+ const base = await this.httpResponse(init);
61
70
  const length = this.types.number({ min: 10, max: 4000 });
62
71
  const result: IResponse = {
63
72
  ...base,
@@ -78,7 +87,7 @@ export class Response {
78
87
  return result;
79
88
  }
80
89
 
81
- redirect(init?: IResponseInit): IResponseRedirect {
90
+ async redirect(init?: IResponseInit): Promise<IResponseRedirect> {
82
91
  const start = this.time.timestamp();
83
92
  const end = this.time.timestamp({ min: start + 1 })
84
93
  const info: IResponseRedirect = {
@@ -86,16 +95,16 @@ export class Response {
86
95
  startTime: start,
87
96
  endTime: end,
88
97
  url: this.internet.uri(),
89
- response: this.httpResponse({ ...init, statusGroup: 3}),
98
+ response: await this.httpResponse({ ...init, statusGroup: 3}),
90
99
  };
91
100
  return info;
92
101
  }
93
102
 
94
- redirects(size=1, init?: IResponseInit): IResponseRedirect[] {
95
- const result: IResponseRedirect[] = [];
103
+ async redirects(size=1, init?: IResponseInit): Promise<IResponseRedirect[]> {
104
+ const result: Promise<IResponseRedirect>[] = [];
96
105
  for (let i = 0; i < size; i++) {
97
106
  result.push(this.redirect(init));
98
107
  }
99
- return result;
108
+ return Promise.all(result);
100
109
  }
101
110
  }
@@ -1,4 +1,4 @@
1
- import { DataMockInit, Internet, Types } from "@pawel-up/data-mock";
1
+ import { IDataMockInit, Internet, Types } from "@pawel-up/data-mock";
2
2
  import { IUrl } from "../../models/Url.js";
3
3
 
4
4
  /**
@@ -8,7 +8,7 @@ export class Url {
8
8
  types: Types;
9
9
  internet: Internet;
10
10
 
11
- constructor(init: DataMockInit={}) {
11
+ constructor(init: IDataMockInit={}) {
12
12
  this.types = new Types(init.seed);
13
13
  this.internet = new Internet(init);
14
14
  }
@@ -1,5 +1,4 @@
1
- import { Internet, Types, DataMockInit, Person, Random } from '@pawel-up/data-mock';
2
- // import { randomValue } from '@pawel-up/data-mock/src/lib/Http.js';
1
+ import { Internet, Types, IDataMockInit, Person, Random } from '@pawel-up/data-mock';
3
2
  import { IUser, Kind as UserKind } from '../../models/store/User.js';
4
3
 
5
4
  export interface IUserInit {
@@ -14,7 +13,7 @@ export class User {
14
13
  internet: Internet;
15
14
  random: Random;
16
15
 
17
- constructor(init: DataMockInit={}) {
16
+ constructor(init: IDataMockInit={}) {
18
17
  this.person = new Person(init);
19
18
  this.types = new Types(init.seed);
20
19
  this.internet = new Internet(init);
@@ -59,6 +59,12 @@ export interface IRequestBaseConfig {
59
59
  * Whether the processor should validate certificates.
60
60
  */
61
61
  validateCertificates?: boolean;
62
+
63
+ /**
64
+ * Optional signal from an `AbortController`.
65
+ * This is populated only when executing a request. This value is opaque for the data store.
66
+ */
67
+ signal?: AbortSignal;
62
68
  }
63
69
 
64
70
  /**
@@ -150,6 +156,12 @@ export class RequestConfig {
150
156
  */
151
157
  sentMessageLimit?: number;
152
158
 
159
+ /**
160
+ * Optional signal from an `AbortController`.
161
+ * This is populated only when executing a request. This value is opaque for the data store.
162
+ */
163
+ signal?: AbortSignal;
164
+
153
165
  static withDefaults(): RequestConfig {
154
166
  return new RequestConfig({
155
167
  kind: Kind,
@@ -209,7 +221,7 @@ export class RequestConfig {
209
221
  new(init: IRequestConfig): void {
210
222
  const {
211
223
  enabled, followRedirects, ignoreSessionCookies, validateCertificates, defaultHeaders, timeout, hosts, variables,
212
- defaultAccept, defaultUserAgent, proxy, proxyPassword, proxyUsername, sentMessageLimit,
224
+ defaultAccept, defaultUserAgent, proxy, proxyPassword, proxyUsername, sentMessageLimit, signal,
213
225
  } = init;
214
226
  this.kind = Kind;
215
227
  if (typeof enabled === 'boolean') {
@@ -282,6 +294,11 @@ export class RequestConfig {
282
294
  } else {
283
295
  this.sentMessageLimit = undefined;
284
296
  }
297
+ if (signal) {
298
+ this.signal = signal;
299
+ } else {
300
+ this.signal = undefined;
301
+ }
285
302
  }
286
303
 
287
304
  toJSON(): IRequestConfig {
@@ -310,6 +327,7 @@ export class RequestConfig {
310
327
  if (Array.isArray(this.variables)) {
311
328
  result.variables = this.variables.map(i => i.toJSON());
312
329
  }
330
+ // DO NOT put the `signal` here.
313
331
  return result;
314
332
  }
315
333
  }
@@ -74,7 +74,7 @@ export class CoreEngine extends HttpEngine {
74
74
  } else {
75
75
  await this.connect();
76
76
  }
77
- if (!this.socket) {
77
+ if (!this.socket || this.aborted) {
78
78
  return;
79
79
  }
80
80
  const message = await this.prepareMessage();
@@ -191,6 +191,31 @@ export abstract class HttpEngine extends EventEmitter {
191
191
  protected mainRejecter?: (err: SerializableError) => void;
192
192
  [mainPromiseSymbol]?: Promise<IRequestLog>;
193
193
 
194
+ protected _signal?: AbortSignal;
195
+
196
+ /**
197
+ * The abort signal to set on this request.
198
+ * Aborts the request when the signal fires.
199
+ * @type {(AbortSignal | undefined)}
200
+ */
201
+ get signal(): AbortSignal | undefined {
202
+ return this._signal;
203
+ }
204
+
205
+ set signal(value: AbortSignal | undefined) {
206
+ const old = this._signal;
207
+ if (old === value) {
208
+ return;
209
+ }
210
+ this._signal = value;
211
+ if (old) {
212
+ old.removeEventListener('abort', this._abortHandler);
213
+ }
214
+ if (value) {
215
+ value.addEventListener('abort', this._abortHandler);
216
+ }
217
+ }
218
+
194
219
  constructor(request: IHttpRequest, opts: HttpEngineOptions = {}) {
195
220
  super();
196
221
  this.request = new HttpRequest({ ...request });
@@ -199,6 +224,11 @@ export abstract class HttpEngine extends EventEmitter {
199
224
  this.sentRequest = new SentRequest({ ...request, startTime: Date.now() });
200
225
  this.uri = this.readUrl(request.url);
201
226
  this.hostHeader = RequestUtils.getHostHeader(request.url);
227
+
228
+ this._abortHandler = this._abortHandler.bind(this);
229
+ if (opts.signal) {
230
+ this.signal = opts.signal;
231
+ }
202
232
  }
203
233
 
204
234
  /**
@@ -245,6 +275,15 @@ export abstract class HttpEngine extends EventEmitter {
245
275
  this.socket = undefined;
246
276
  }
247
277
 
278
+ /**
279
+ * Handler for the `abort` event on the `AbortSignal`.
280
+ */
281
+ protected _abortHandler(): void {
282
+ const e = new SerializableError('Request aborted', 3);
283
+ this._errorRequest(e);
284
+ this.abort();
285
+ }
286
+
248
287
  /**
249
288
  * Sends the request.
250
289
  */
@@ -118,4 +118,10 @@ export interface IProjectRunnerOptions {
118
118
  * When not set it does not read system variables.
119
119
  */
120
120
  variables?: boolean | string[] | Record<string, string>;
121
+
122
+ /**
123
+ * Optional signal from an `AbortController`.
124
+ * It aborts the execution when the ``abort` event is dispatched.
125
+ */
126
+ signal?: AbortSignal;
121
127
  }
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  import { HttpProject } from '../../models/HttpProject.js';
6
6
  import { IProjectExecutionLog, IProjectExecutionIteration } from '../reporters/Reporter.js';
7
7
  import { BaseRunner } from './BaseRunner.js';
8
+ import { State } from './enums.js';
8
9
  import { IProjectParallelRunnerOptions, IProjectParallelWorkerOptions } from './InteropInterfaces.js'
9
10
 
10
11
  const numCPUs = cpus().length;
@@ -74,9 +75,13 @@ export class ProjectParallelRunner extends BaseRunner {
74
75
  constructor(project: HttpProject, opts: IProjectParallelRunnerOptions = {}) {
75
76
  super();
76
77
  this.project = project;
77
- this.options = opts || {};
78
+ this.options = opts;
78
79
 
79
80
  this._exitHandler = this._exitHandler.bind(this);
81
+ this._abortHandler = this._abortHandler.bind(this);
82
+ if (opts.signal) {
83
+ this.signal = opts.signal;
84
+ }
80
85
  }
81
86
 
82
87
  execute(): Promise<IProjectExecutionLog> {
@@ -87,7 +92,70 @@ export class ProjectParallelRunner extends BaseRunner {
87
92
  });
88
93
  }
89
94
 
95
+ protected _state: State = State.Idle;
96
+
97
+ get state(): State {
98
+ return this._state;
99
+ }
100
+
101
+ protected _signal?: AbortSignal;
102
+
103
+ /**
104
+ * The abort signal to set on this request.
105
+ * Aborts the request when the signal fires.
106
+ * @type {(AbortSignal | undefined)}
107
+ */
108
+ get signal(): AbortSignal | undefined {
109
+ return this._signal;
110
+ }
111
+
112
+ set signal(value: AbortSignal | undefined) {
113
+ const old = this._signal;
114
+ if (old === value) {
115
+ return;
116
+ }
117
+ this._signal = value;
118
+ if (old) {
119
+ old.removeEventListener('abort', this._abortHandler);
120
+ }
121
+ if (value) {
122
+ value.addEventListener('abort', this._abortHandler);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Aborts the current run.
128
+ * The promise returned by the `execute()` method will reject if not yet resolved.
129
+ */
130
+ abort(): void {
131
+ this._state = State.Aborted;
132
+ const { workers } = this;
133
+ workers.forEach((info) => {
134
+ if (info.status !== 'error') {
135
+ try {
136
+ info.worker.destroy();
137
+ } catch (e) {
138
+ // ...
139
+ }
140
+ info.status = 'error';
141
+ }
142
+ });
143
+ if (this.mainRejecter) {
144
+ this.mainRejecter!(new Error(`The execution has been aborted.`));
145
+ this.mainRejecter = undefined;
146
+ this.mainResolver = undefined;
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Handler for the `abort` event on the `AbortSignal`.
152
+ */
153
+ protected _abortHandler(): void {
154
+ this.abort();
155
+ }
156
+
90
157
  private _execute(): void {
158
+ this._state = State.Running as State;
91
159
  try {
92
160
  cluster.setupPrimary({
93
161
  exec: join(__dirname, 'ProjectRunnerWorker.js'),
@@ -105,6 +173,9 @@ export class ProjectParallelRunner extends BaseRunner {
105
173
  } catch (e) {
106
174
  const cause = e as Error;
107
175
  this.mainRejecter!(cause);
176
+ this.mainResolver = undefined
177
+ this.mainRejecter = undefined
178
+ this._state = State.Idle as State;
108
179
  }
109
180
  }
110
181
 
@@ -211,7 +282,10 @@ export class ProjectParallelRunner extends BaseRunner {
211
282
  this.endTime = Date.now();
212
283
  const report = await this.createReport();
213
284
  this.mainResolver(report);
285
+ this.mainResolver = undefined
286
+ this.mainRejecter = undefined
214
287
  cluster.off('exit', this._exitHandler);
288
+ this._state = State.Idle as State;
215
289
  }
216
290
 
217
291
  private setRunError(worker: Worker, message: IWorkerMessage): void {