@opentap/runner-client 2.0.0-alpha.2.9 → 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.
@@ -26,9 +26,11 @@ export declare class BaseClient {
26
26
  * @param subject The subject to request
27
27
  * @param payload (optional)
28
28
  * @param options (optional)
29
+ * @param isFullSubject (optional) If true, use the subject as request subject
30
+ * without appending it to the baseSubject
29
31
  * @returns Promise of an object
30
32
  */
31
- protected request<T>(subject: string, payload?: any, options?: RequestOptions): Promise<T>;
33
+ protected request<T>(subject: string, payload?: any, options?: RequestOptions, isFullSubject?: boolean): Promise<T>;
32
34
  /**
33
35
  * Handle the error
34
36
  * @param error
@@ -49,7 +51,7 @@ export declare class BaseClient {
49
51
  */
50
52
  protected subscribe(subject: string, options: SubscriptionOptions): Subscription;
51
53
  /**
52
- * Send a request to the nats server.
54
+ * Send an object to the nats server with chunks.
53
55
  * @param subject The subject to request
54
56
  * @param payload (optional)
55
57
  * @param options (optional)
@@ -57,13 +59,13 @@ export declare class BaseClient {
57
59
  */
58
60
  protected sendChunked<T>(subject: string, payload?: any, options?: RequestOptions): Promise<T>;
59
61
  /**
60
- * Send a request to the nats server.
62
+ * Request an object to the nats server with chunks.
61
63
  * @param subject The subject to request
62
64
  * @param payload (optional)
63
65
  * @param options (optional)
64
66
  * @returns Promise of an object
65
67
  */
66
- protected requestChunked<T>(subject: string, options?: RequestOptions): Promise<T>;
68
+ protected requestChunked<T>(subject: string, replySubject: string, payload: any, options?: RequestOptions, isFullSubject?: boolean): Promise<T>;
67
69
  /**
68
70
  * Check if the the response is an error from the server.
69
71
  * @param {any} response
package/lib/BaseClient.js CHANGED
@@ -56,7 +56,6 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
56
56
  };
57
57
  import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileDescriptor, ListItemType, ProfileGroup, } from './DTOs';
58
58
  import { Empty, ErrorCode, JSONCodec, StringCodec, connect, headers, } from 'nats.ws';
59
- import { v4 as uuidv4 } from 'uuid';
60
59
  var DEFAULT_TIMEOUT = 6000;
61
60
  var BaseClient = /** @class */ (function () {
62
61
  function BaseClient(baseSubject, options) {
@@ -107,16 +106,18 @@ var BaseClient = /** @class */ (function () {
107
106
  * @param subject The subject to request
108
107
  * @param payload (optional)
109
108
  * @param options (optional)
109
+ * @param isFullSubject (optional) If true, use the subject as request subject
110
+ * without appending it to the baseSubject
110
111
  * @returns Promise of an object
111
112
  */
112
- BaseClient.prototype.request = function (subject, payload, options) {
113
+ BaseClient.prototype.request = function (subject, payload, options, isFullSubject) {
113
114
  return __awaiter(this, void 0, void 0, function () {
114
115
  var stringCodec, data, headers, opts;
115
116
  var _this = this;
116
117
  return __generator(this, function (_a) {
117
118
  switch (_a.label) {
118
119
  case 0:
119
- subject = "".concat(this.baseSubject, ".Request.").concat(subject);
120
+ subject = isFullSubject ? subject : "".concat(this.baseSubject, ".Request.").concat(subject);
120
121
  if (!this.connection)
121
122
  return [2 /*return*/, Promise.reject("".concat(subject, ": Connection is down! Please try again!"))];
122
123
  if (this.connection.isClosed())
@@ -189,7 +190,7 @@ var BaseClient = /** @class */ (function () {
189
190
  return this.connection.subscribe(natsSubject, options);
190
191
  };
191
192
  /**
192
- * Send a request to the nats server.
193
+ * Send an object to the nats server with chunks.
193
194
  * @param subject The subject to request
194
195
  * @param payload (optional)
195
196
  * @param options (optional)
@@ -197,88 +198,54 @@ var BaseClient = /** @class */ (function () {
197
198
  */
198
199
  BaseClient.prototype.sendChunked = function (subject, payload, options) {
199
200
  return __awaiter(this, void 0, void 0, function () {
200
- var requestSubject, stringCodec, data, headers, opts, fileDescriptor, getChunk, message, i, response, jsonCodec;
201
+ var stringCodec, data, headers, opts, fileDescriptor, getChunk, dataSubject, i;
202
+ var _this = this;
201
203
  return __generator(this, function (_a) {
202
204
  switch (_a.label) {
203
205
  case 0:
204
- requestSubject = "".concat(this.baseSubject, ".Request.").concat(subject);
205
206
  if (!this.connection)
206
- return [2 /*return*/, Promise.reject("".concat(requestSubject, ": Connection is down! Please try again!"))];
207
+ return [2 /*return*/, Promise.reject("".concat(subject, ": Connection is down! Please try again!"))];
207
208
  if (this.connection.isClosed())
208
- return [2 /*return*/, Promise.reject("".concat(requestSubject, ": Connection has been closed! Please reconnect!"))];
209
+ return [2 /*return*/, Promise.reject("".concat(subject, ": Connection has been closed! Please reconnect!"))];
209
210
  stringCodec = StringCodec();
210
211
  data = payload ? stringCodec.encode(JSON.stringify(payload)) : Empty;
211
212
  headers = this.buildHeaders();
212
213
  opts = __assign(__assign({}, options), { timeout: this.timeout, headers: headers });
213
214
  fileDescriptor = new FileDescriptor(data.length);
214
215
  if (!fileDescriptor.numberOfChunks)
215
- return [2 /*return*/, Promise.reject("".concat(requestSubject, ": File is empty!"))];
216
+ return [2 /*return*/, Promise.reject("".concat(subject, ": File is empty!"))];
216
217
  getChunk = function (chunk) {
217
218
  var offset = chunk * fileDescriptor.chunkSize;
218
219
  return data.slice(offset, offset + fileDescriptor.chunkSize);
219
220
  };
220
- this.request(subject, fileDescriptor);
221
- i = 0;
222
- _a.label = 1;
221
+ return [4 /*yield*/, this.request(subject, fileDescriptor, opts)];
223
222
  case 1:
224
- if (!(i < fileDescriptor.numberOfChunks)) return [3 /*break*/, 4];
225
- return [4 /*yield*/, this.connection.request(requestSubject, getChunk(i), opts)];
226
- case 2:
227
- message = _a.sent();
228
- _a.label = 3;
229
- case 3:
230
- i++;
231
- return [3 /*break*/, 1];
232
- case 4:
233
- if (message && message.data.length !== 0) {
234
- jsonCodec = JSONCodec();
235
- response = jsonCodec.decode(message.data);
223
+ dataSubject = _a.sent();
224
+ for (i = 0; i < fileDescriptor.numberOfChunks; i++) {
225
+ this.connection.publish(dataSubject, getChunk(i), opts);
236
226
  }
237
- return [2 /*return*/, this.isErrorResponse(response) ? Promise.reject(ErrorResponse.fromJS(response)) : Promise.resolve(response)];
238
- }
239
- });
240
- });
241
- };
242
- /**
243
- * Send a request to the nats server.
244
- * @param subject The subject to request
245
- * @param payload (optional)
246
- * @param options (optional)
247
- * @returns Promise of an object
248
- */
249
- BaseClient.prototype.requestChunked = function (subject, options) {
250
- return __awaiter(this, void 0, void 0, function () {
251
- var replySubject, requestSubject, stringCodec, data, headers, opts, fileDescriptor;
252
- var _this = this;
253
- return __generator(this, function (_a) {
254
- switch (_a.label) {
255
- case 0:
256
- replySubject = "_INBOX.".concat(uuidv4());
257
- requestSubject = "".concat(this.baseSubject, ".Request.").concat(subject);
258
- if (!this.connection)
259
- return [2 /*return*/, Promise.reject("".concat(requestSubject, ": Connection is down! Please try again!"))];
260
- if (this.connection.isClosed())
261
- return [2 /*return*/, Promise.reject("".concat(requestSubject, ": Connection has been closed! Please reconnect!"))];
262
- stringCodec = StringCodec();
263
- data = stringCodec.encode(JSON.stringify(replySubject));
264
- headers = this.buildHeaders();
265
- opts = __assign(__assign({}, options), { timeout: this.timeout, headers: headers });
266
- return [4 /*yield*/, this.request(subject, data, opts)];
267
- case 1:
268
- fileDescriptor = _a.sent();
269
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
270
227
  return [2 /*return*/, new Promise(function (resolve, reject) {
228
+ if (!_this.connection) {
229
+ return Promise.reject('No nats connection.');
230
+ }
271
231
  var combinedResult = new Uint8Array([]);
272
- var received = 0;
273
- var subscription = _this.connection.subscribe(replySubject);
232
+ // Subscribe to dataSubject before sending the terminating message to ensure we are listening before the server starts responding
233
+ var subscription = _this.connection.subscribe(dataSubject);
234
+ // Publish an empty message to indicate that we are ready to listen
235
+ _this.connection.publish(dataSubject, Empty, opts);
236
+ var first = true;
274
237
  subscription.callback = function (error, message) {
238
+ // The first message is the empty message we published above.
239
+ // We should discard this message before we proceed
240
+ if (first === true) {
241
+ first = false;
242
+ return;
243
+ }
275
244
  if (error) {
276
245
  reject(error);
277
246
  }
278
247
  combinedResult = new Uint8Array(__spreadArray(__spreadArray([], Array.from(combinedResult), true), Array.from(message === null || message === void 0 ? void 0 : message.data), true));
279
- received++;
280
- message.respond(Empty);
281
- if (received === fileDescriptor.numberOfChunks) {
248
+ if ((message === null || message === void 0 ? void 0 : message.data.length) === 0) {
282
249
  resolve(combinedResult);
283
250
  }
284
251
  };
@@ -291,6 +258,63 @@ var BaseClient = /** @class */ (function () {
291
258
  });
292
259
  });
293
260
  };
261
+ /**
262
+ * Request an object to the nats server with chunks.
263
+ * @param subject The subject to request
264
+ * @param payload (optional)
265
+ * @param options (optional)
266
+ * @returns Promise of an object
267
+ */
268
+ BaseClient.prototype.requestChunked = function (subject, replySubject, payload, options, isFullSubject) {
269
+ return __awaiter(this, void 0, void 0, function () {
270
+ var fileSize;
271
+ var _this = this;
272
+ return __generator(this, function (_a) {
273
+ if (!this.connection)
274
+ return [2 /*return*/, Promise.reject("".concat(subject, ": Connection is down! Please try again!"))];
275
+ if (this.connection.isClosed())
276
+ return [2 /*return*/, Promise.reject("".concat(subject, ": Connection has been closed! Please reconnect!"))];
277
+ fileSize = -1;
278
+ return [2 /*return*/, new Promise(function (resolve, reject) {
279
+ var combinedResult = new Uint8Array([]);
280
+ // Subscribe to the subject before starting the process
281
+ var subscription = _this.connection.subscribe(replySubject);
282
+ var resolveIfCompleted = function () {
283
+ if (combinedResult.length === fileSize) {
284
+ subscription.unsubscribe();
285
+ resolve(combinedResult);
286
+ }
287
+ };
288
+ subscription.callback = function (error, message) {
289
+ if (error) {
290
+ reject(error);
291
+ }
292
+ combinedResult = new Uint8Array(__spreadArray(__spreadArray([], Array.from(combinedResult), true), Array.from(message === null || message === void 0 ? void 0 : message.data), true));
293
+ resolveIfCompleted();
294
+ };
295
+ var headers = _this.buildHeaders();
296
+ var opts = __assign(__assign({}, options), { timeout: _this.timeout, headers: headers });
297
+ // Request the file descriptor from the runner by posting the reply subject
298
+ return _this.request(subject, payload, opts, isFullSubject)
299
+ .then(function (fileDescriptor) { return FileDescriptor.fromJS(fileDescriptor); })
300
+ .then(function (fileDescriptor) {
301
+ fileSize = fileDescriptor.fileSize;
302
+ resolveIfCompleted();
303
+ })
304
+ .catch(function (error) {
305
+ subscription.unsubscribe();
306
+ throw error;
307
+ });
308
+ }).then(function (byteArray) {
309
+ if (byteArray.length !== fileSize)
310
+ return Promise.reject("Unexpected response size. Expected ".concat(fileSize, " bytes, but got ").concat(byteArray.length, "."));
311
+ var jsonCodec = JSONCodec();
312
+ var response = jsonCodec.decode(byteArray);
313
+ return _this.isErrorResponse(response) ? Promise.reject(ErrorResponse.fromJS(response)) : Promise.resolve(response);
314
+ })];
315
+ });
316
+ });
317
+ };
294
318
  /**
295
319
  * Check if the the response is an error from the server.
296
320
  * @param {any} response
package/lib/DTOs.d.ts CHANGED
@@ -418,29 +418,13 @@ export declare class PasswordControl extends Setting implements IPasswordControl
418
418
  export interface IPasswordControl extends ISetting {
419
419
  password?: string | undefined;
420
420
  }
421
- export declare class PictureControl extends Setting implements IPictureControl {
422
- description?: string | undefined;
423
- mimeType?: string | undefined;
424
- resource?: Resource | undefined;
425
- constructor(data?: IPictureControl);
426
- init(_data?: any): void;
427
- static fromJS(data: any): PictureControl;
428
- toJSON(data?: any): any;
429
- }
430
- export interface IPictureControl extends ISetting {
431
- description?: string | undefined;
432
- mimeType?: string | undefined;
433
- resource?: Resource | undefined;
434
- }
435
- export declare class Resource implements IResource {
436
- source?: string | undefined;
437
- constructor(data?: IResource);
438
- init(_data?: any): void;
439
- static fromJS(data: any): Resource;
440
- toJSON(data?: any): any;
421
+ export declare class TestPlanRequest implements ITestPlanRequest {
422
+ properties?: string[] | null | undefined;
423
+ subject?: string | undefined;
441
424
  }
442
- export interface IResource {
443
- source?: string | undefined;
425
+ export interface ITestPlanRequest {
426
+ properties?: string[] | null | undefined;
427
+ subject?: string | undefined;
444
428
  }
445
429
  export declare class FileDescriptor implements IFileDescriptor {
446
430
  numberOfChunks: number;
@@ -449,7 +433,7 @@ export declare class FileDescriptor implements IFileDescriptor {
449
433
  private readonly defaultChunkSize;
450
434
  constructor(fileSize: number, chunkSize?: number);
451
435
  init(_data?: any): void;
452
- static fromJS(data: any): Resource;
436
+ static fromJS(data: any): FileDescriptor;
453
437
  toJSON(data?: any): any;
454
438
  }
455
439
  export interface IFileDescriptor {
package/lib/DTOs.js CHANGED
@@ -1238,66 +1238,12 @@ var PasswordControl = /** @class */ (function (_super) {
1238
1238
  return PasswordControl;
1239
1239
  }(Setting));
1240
1240
  export { PasswordControl };
1241
- var PictureControl = /** @class */ (function (_super) {
1242
- __extends(PictureControl, _super);
1243
- function PictureControl(data) {
1244
- var _this = _super.call(this, data) || this;
1245
- _this._discriminator = 'PictureControl';
1246
- return _this;
1247
- }
1248
- PictureControl.prototype.init = function (_data) {
1249
- _super.prototype.init.call(this, _data);
1250
- if (_data) {
1251
- this.description = _data['Description'];
1252
- this.mimeType = _data['MimeType'];
1253
- this.resource = _data['Resource'] ? Resource.fromJS(_data['Resource']) : undefined;
1254
- }
1255
- };
1256
- PictureControl.fromJS = function (data) {
1257
- data = typeof data === 'object' ? data : {};
1258
- var result = new PictureControl();
1259
- result.init(data);
1260
- return result;
1261
- };
1262
- PictureControl.prototype.toJSON = function (data) {
1263
- data = typeof data === 'object' ? data : {};
1264
- data['Description'] = this.description;
1265
- data['MimeType'] = this.mimeType;
1266
- data['Resource'] = this.resource ? this.resource.toJSON() : undefined;
1267
- _super.prototype.toJSON.call(this, data);
1268
- return data;
1269
- };
1270
- return PictureControl;
1271
- }(Setting));
1272
- export { PictureControl };
1273
- var Resource = /** @class */ (function () {
1274
- function Resource(data) {
1275
- if (data) {
1276
- for (var property in data) {
1277
- if (Object.prototype.hasOwnProperty.call(data, property))
1278
- this[property] = data[property];
1279
- }
1280
- }
1241
+ var TestPlanRequest = /** @class */ (function () {
1242
+ function TestPlanRequest() {
1281
1243
  }
1282
- Resource.prototype.init = function (_data) {
1283
- if (_data) {
1284
- this.source = _data['Source'];
1285
- }
1286
- };
1287
- Resource.fromJS = function (data) {
1288
- data = typeof data === 'object' ? data : {};
1289
- var result = new Resource();
1290
- result.init(data);
1291
- return result;
1292
- };
1293
- Resource.prototype.toJSON = function (data) {
1294
- data = typeof data === 'object' ? data : {};
1295
- data['Source'] = this.source;
1296
- return data;
1297
- };
1298
- return Resource;
1244
+ return TestPlanRequest;
1299
1245
  }());
1300
- export { Resource };
1246
+ export { TestPlanRequest };
1301
1247
  var FileDescriptor = /** @class */ (function () {
1302
1248
  function FileDescriptor(fileSize, chunkSize) {
1303
1249
  var _a;
@@ -1318,7 +1264,7 @@ var FileDescriptor = /** @class */ (function () {
1318
1264
  };
1319
1265
  FileDescriptor.fromJS = function (data) {
1320
1266
  data = typeof data === 'object' ? data : {};
1321
- var result = new Resource();
1267
+ var result = new FileDescriptor(0);
1322
1268
  result.init(data);
1323
1269
  return result;
1324
1270
  };
@@ -1,4 +1,4 @@
1
- import { BreakPoints, CommonContext, CommonSettings, DataGridControl, Image, Interaction, ListItemType, LogList, Parameter, RepositoryPackageDefinition, RepositoryPackageReference, Resource, Result, RunStatus, SessionEvent, Setting, TestPlan, TestRun, TestStepType, TestStepValidationError, WatchDog } from './DTOs';
1
+ import { BreakPoints, CommonContext, CommonSettings, DataGridControl, Image, Interaction, ListItemType, LogList, Parameter, RepositoryPackageDefinition, RepositoryPackageReference, Result, RunStatus, SessionEvent, Setting, TestPlan, TestRun, TestStepType, TestStepValidationError, WatchDog } from './DTOs';
2
2
  import { ConnectionOptions, NatsError, Subscription, SubscriptionOptions } from 'nats.ws';
3
3
  import { BaseClient } from './BaseClient';
4
4
  export declare class SessionClient extends BaseClient {
@@ -86,11 +86,6 @@ export declare class SessionClient extends BaseClient {
86
86
  * @return Test plan retrieved
87
87
  */
88
88
  getTestPlanXML(): Promise<string>;
89
- /**
90
- * Retrieve loaded test plan XML
91
- * @return Test plan retrieved
92
- */
93
- downloadResource(resource: Resource): Promise<Uint8Array>;
94
89
  /**
95
90
  * Load test plan using a test plan TapPackage from a repository
96
91
  * @param {RepositoryPackageDefinition} packageReference
@@ -27,6 +27,7 @@ var __assign = (this && this.__assign) || function () {
27
27
  import { BreakPoints, CommonContext, CommonSettings, DataGridControl, Image, Interaction, ListItemType, LogList, Result, RunStatus, SessionEvent, Setting, TestPlan, TestRun, TestStepType, TestStepValidationError, WatchDog, } from './DTOs';
28
28
  import { JSONCodec } from 'nats.ws';
29
29
  import { BaseClient } from './BaseClient';
30
+ import { v4 as uuidv4 } from 'uuid';
30
31
  var SessionClient = /** @class */ (function (_super) {
31
32
  __extends(SessionClient, _super);
32
33
  function SessionClient(baseSubject, options) {
@@ -204,20 +205,9 @@ var SessionClient = /** @class */ (function (_super) {
204
205
  * @return Test plan retrieved
205
206
  */
206
207
  SessionClient.prototype.getTestPlanXML = function () {
207
- return this.requestChunked('GetTestPlanXML').then(this.success()).catch(this.error());
208
- };
209
- /**
210
- * Retrieve loaded test plan XML
211
- * @return Test plan retrieved
212
- */
213
- SessionClient.prototype.downloadResource = function (resource) {
214
- var _a;
215
- var runnerResourcePrefix = 'subject://';
216
- if (!((_a = resource.source) === null || _a === void 0 ? void 0 : _a.startsWith(runnerResourcePrefix))) {
217
- return Promise.reject('The source of the provided resource is not a nats subject.');
218
- }
219
- var subject = resource.source.replace(runnerResourcePrefix, '');
220
- return this.requestChunked(subject).then(this.success()).catch(this.error());
208
+ // Generate a unique subject where the Runner will publish the chunks
209
+ var replySubject = "_INBOX.".concat(uuidv4());
210
+ return this.requestChunked('GetTestPlanXML', replySubject, replySubject).then(this.success()).catch(this.error());
221
211
  };
222
212
  /**
223
213
  * Load test plan using a test plan TapPackage from a repository
@@ -240,7 +230,8 @@ var SessionClient = /** @class */ (function (_super) {
240
230
  * @return Test plan resources opened.
241
231
  */
242
232
  SessionClient.prototype.resourcesOpen = function () {
243
- return this.request('ResourcesOpen')
233
+ var replySubject = "_INBOX.".concat(uuidv4());
234
+ return this.requestChunked('ResourcesOpen', replySubject, replySubject)
244
235
  .then(function (testPlanJs) { return TestPlan.fromJS(testPlanJs); })
245
236
  .then(this.success())
246
237
  .catch(this.error());
@@ -250,7 +241,8 @@ var SessionClient = /** @class */ (function (_super) {
250
241
  * @return Test plan resources closed.
251
242
  */
252
243
  SessionClient.prototype.resourcesClose = function () {
253
- return this.request('ResourcesClose')
244
+ var replySubject = "_INBOX.".concat(uuidv4());
245
+ return this.requestChunked('ResourcesClose', replySubject, replySubject)
254
246
  .then(function (testPlanJs) { return TestPlan.fromJS(testPlanJs); })
255
247
  .then(this.success())
256
248
  .catch(this.error());
@@ -285,7 +277,12 @@ var SessionClient = /** @class */ (function (_super) {
285
277
  * @return Test plan retrieved
286
278
  */
287
279
  SessionClient.prototype.getTestPlan = function (properties) {
288
- return this.request('GetTestPlan', properties)
280
+ var replySubject = "_INBOX.".concat(uuidv4());
281
+ var payload = {
282
+ subject: replySubject,
283
+ properties: properties,
284
+ };
285
+ return this.requestChunked('GetTestPlan', replySubject, payload)
289
286
  .then(function (testPlanJs) { return TestPlan.fromJS(testPlanJs); })
290
287
  .then(this.success())
291
288
  .catch(this.error());
@@ -296,7 +293,7 @@ var SessionClient = /** @class */ (function (_super) {
296
293
  * @return Test plan changed
297
294
  */
298
295
  SessionClient.prototype.setTestPlan = function (plan) {
299
- return this.request('SetTestPlan', plan)
296
+ return this.sendChunked('SetTestPlan', plan)
300
297
  .then(function (testPlanJs) { return TestPlan.fromJS(testPlanJs); })
301
298
  .then(this.success())
302
299
  .catch(this.error());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentap/runner-client",
3
- "version": "2.0.0-alpha.2.9",
3
+ "version": "2.0.0",
4
4
  "description": "This is the web client for the OpenTAP Runner.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",