@webex/webex-core 3.8.0-next.21 → 3.8.0-next.22

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 (35) hide show
  1. package/dist/index.js +6 -6
  2. package/dist/index.js.map +1 -1
  3. package/dist/lib/batcher.js +1 -1
  4. package/dist/lib/credentials/credentials.js +1 -1
  5. package/dist/lib/credentials/token.js +1 -1
  6. package/dist/lib/services/services.js +1 -1
  7. package/dist/lib/services-v2/constants.js.map +1 -1
  8. package/dist/lib/services-v2/index.js +5 -5
  9. package/dist/lib/services-v2/index.js.map +1 -1
  10. package/dist/lib/services-v2/service-catalog.js +26 -30
  11. package/dist/lib/services-v2/service-catalog.js.map +1 -1
  12. package/dist/lib/services-v2/service-detail.js +94 -0
  13. package/dist/lib/services-v2/service-detail.js.map +1 -0
  14. package/dist/lib/services-v2/service-fed-ramp.js.map +1 -1
  15. package/dist/lib/services-v2/services-v2.js +70 -48
  16. package/dist/lib/services-v2/services-v2.js.map +1 -1
  17. package/dist/lib/services-v2/types.js +7 -0
  18. package/dist/lib/services-v2/types.js.map +1 -0
  19. package/dist/plugins/logger.js +1 -1
  20. package/dist/webex-core.js +2 -2
  21. package/package.json +13 -13
  22. package/src/index.js +1 -1
  23. package/src/lib/services-v2/{index.js → index.ts} +1 -1
  24. package/src/lib/services-v2/{service-catalog.js → service-catalog.ts} +41 -47
  25. package/src/lib/services-v2/service-detail.ts +97 -0
  26. package/src/lib/services-v2/services-v2.js +41 -24
  27. package/src/lib/services-v2/types.ts +12 -0
  28. package/test/fixtures/host-catalog-v2.js +18 -16
  29. package/test/unit/spec/services-v2/service-detail.ts +147 -0
  30. package/test/unit/spec/services-v2/services-v2.js +12 -14
  31. package/dist/lib/services-v2/service-url.js +0 -119
  32. package/dist/lib/services-v2/service-url.js.map +0 -1
  33. package/src/lib/services-v2/service-url.js +0 -124
  34. /package/src/lib/services-v2/{constants.js → constants.ts} +0 -0
  35. /package/src/lib/services-v2/{service-fed-ramp.js → service-fed-ramp.ts} +0 -0
@@ -20,4 +20,4 @@ export {default as ServiceInterceptorV2} from './interceptors/service';
20
20
  export {default as ServerErrorInterceptorV2} from './interceptors/server-error';
21
21
  export {default as HostMapInterceptorV2} from './interceptors/hostmap';
22
22
  export {default as ServiceCatalogV2} from './service-catalog';
23
- export {default as ServiceUrlV2} from './service-url';
23
+ export {default as ServiceDetail} from './service-detail';
@@ -3,7 +3,8 @@ import Url from 'url';
3
3
  import AmpState from 'ampersand-state';
4
4
 
5
5
  import {union} from 'lodash';
6
- import ServiceUrl from './service-url';
6
+ import ServiceDetail from './service-detail';
7
+ import {IServiceDetail} from './types';
7
8
 
8
9
  /* eslint-disable no-underscore-dangle */
9
10
  /**
@@ -56,13 +57,13 @@ const ServiceCatalog = AmpState.extend({
56
57
 
57
58
  /**
58
59
  * @private
59
- * Search the service url array to locate a `ServiceUrl`
60
+ * Search the service url array to locate a `ServiceDetail`
60
61
  * class object based on its name.
61
62
  * @param {string} name
62
63
  * @param {string} [serviceGroup]
63
- * @returns {ServiceUrl}
64
+ * @returns {IServiceDetail}
64
65
  */
65
- _getUrl(name, serviceGroup) {
66
+ _getUrl(name: string, serviceGroup: string): IServiceDetail | undefined {
66
67
  const serviceUrls =
67
68
  typeof serviceGroup === 'string'
68
69
  ? this.serviceGroups[serviceGroup] || []
@@ -74,16 +75,16 @@ const ServiceCatalog = AmpState.extend({
74
75
  ...this.serviceGroups.discovery,
75
76
  ];
76
77
 
77
- return serviceUrls.find((serviceUrl) => serviceUrl.name === name);
78
+ return serviceUrls.find((serviceUrl: IServiceDetail) => serviceUrl.serviceName === name);
78
79
  },
79
80
 
80
81
  /**
81
82
  * @private
82
- * Generate an array of `ServiceUrl`s that is organized from highest auth
83
+ * Generate an array of `ServiceDetail`s that is organized from highest auth
83
84
  * level to lowest auth level.
84
- * @returns {Array<ServiceUrl>} - array of `ServiceUrl`s
85
+ * @returns {Array<IServiceDetail>} - array of `ServiceDetail`s
85
86
  */
86
- _listServiceUrls() {
87
+ _listServiceUrls(): Array<IServiceDetail> {
87
88
  return [
88
89
  ...this.serviceGroups.override,
89
90
  ...this.serviceGroups.postauth,
@@ -95,39 +96,37 @@ const ServiceCatalog = AmpState.extend({
95
96
 
96
97
  /**
97
98
  * @private
98
- * Safely load one or more `ServiceUrl`s into this `Services` instance.
99
+ * Safely load one or more `ServiceDetail`s into this `Services` instance.
99
100
  * @param {string} serviceGroup
100
- * @param {Array<ServiceUrl>} services
101
+ * @param {Array<IServiceDetail>} services
101
102
  * @returns {Services}
102
103
  */
103
- _loadServiceUrls(serviceGroup, services) {
104
+ _loadServiceUrls(serviceGroup: string, services: Array<IServiceDetail>): void {
104
105
  // declare namespaces outside of loop
105
- let existingService;
106
+ let existingService: IServiceDetail | undefined;
106
107
 
107
108
  services.forEach((service) => {
108
- existingService = this._getUrl(service.name, serviceGroup);
109
+ existingService = this._getUrl(service.serviceName, serviceGroup);
109
110
 
110
111
  if (!existingService) {
111
112
  this.serviceGroups[serviceGroup].push(service);
112
113
  }
113
114
  });
114
-
115
- return this;
116
115
  },
117
116
 
118
117
  /**
119
118
  * @private
120
- * Safely unload one or more `ServiceUrl`s into this `Services` instance
119
+ * Safely unload one or more `ServiceDetail`s into this `Services` instance
121
120
  * @param {string} serviceGroup
122
- * @param {Array<ServiceUrl>} services
121
+ * @param {Array<IServiceDetail>} services
123
122
  * @returns {Services}
124
123
  */
125
- _unloadServiceUrls(serviceGroup, services) {
124
+ _unloadServiceUrls(serviceGroup: string, services: Array<IServiceDetail>): void {
126
125
  // declare namespaces outside of loop
127
- let existingService;
126
+ let existingService: IServiceDetail | undefined;
128
127
 
129
128
  services.forEach((service) => {
130
- existingService = this._getUrl(service.name, serviceGroup);
129
+ existingService = this._getUrl(service.serviceName, serviceGroup);
131
130
 
132
131
  if (existingService) {
133
132
  this.serviceGroups[serviceGroup].splice(
@@ -136,8 +135,6 @@ const ServiceCatalog = AmpState.extend({
136
135
  );
137
136
  }
138
137
  });
139
-
140
- return this;
141
138
  },
142
139
 
143
140
  /**
@@ -145,7 +142,7 @@ const ServiceCatalog = AmpState.extend({
145
142
  *
146
143
  * @returns {void}
147
144
  */
148
- clean() {
145
+ clean(): void {
149
146
  this.serviceGroups.preauth.length = 0;
150
147
  this.serviceGroups.signin.length = 0;
151
148
  this.serviceGroups.postauth.length = 0;
@@ -160,7 +157,7 @@ const ServiceCatalog = AmpState.extend({
160
157
  * @param {string} url - Must be parsable by `Url`
161
158
  * @returns {string} - ClusterId of a given url
162
159
  */
163
- findClusterId(url) {
160
+ findClusterId(url: string): string | undefined {
164
161
  const incomingUrlObj = Url.parse(url);
165
162
  let serviceUrlObj;
166
163
 
@@ -205,7 +202,7 @@ const ServiceCatalog = AmpState.extend({
205
202
  * @returns {string} service.name
206
203
  * @returns {string} service.url
207
204
  */
208
- findServiceFromClusterId({clusterId, priorityHost = true, serviceGroup} = {}) {
205
+ findServiceFromClusterId({clusterId, priorityHost = true, serviceGroup}) {
209
206
  const serviceUrls =
210
207
  typeof serviceGroup === 'string'
211
208
  ? this.serviceGroups[serviceGroup] || []
@@ -234,9 +231,9 @@ const ServiceCatalog = AmpState.extend({
234
231
  /**
235
232
  * Find a service based on the provided url.
236
233
  * @param {string} url - Must be parsable by `Url`
237
- * @returns {serviceUrl} - ServiceUrl assocated with provided url
234
+ * @returns {IServiceDetail} - ServiceDetail assocated with provided url
238
235
  */
239
- findServiceUrlFromUrl(url) {
236
+ findServiceUrlFromUrl(url: string): IServiceDetail | undefined {
240
237
  const serviceUrls = [
241
238
  ...this.serviceGroups.discovery,
242
239
  ...this.serviceGroups.preauth,
@@ -273,7 +270,7 @@ const ServiceCatalog = AmpState.extend({
273
270
  * @param {string} url - The url to match the allowed domains against.
274
271
  * @returns {string} - The matching allowed domain.
275
272
  */
276
- findAllowedDomain(url) {
273
+ findAllowedDomain(url: string): string {
277
274
  const urlObj = Url.parse(url);
278
275
 
279
276
  if (!urlObj.host) {
@@ -290,7 +287,7 @@ const ServiceCatalog = AmpState.extend({
290
287
  * @param {string} serviceGroup
291
288
  * @returns {string}
292
289
  */
293
- get(name, priorityHost, serviceGroup) {
290
+ get(name: string, priorityHost: boolean, serviceGroup: string): string | undefined {
294
291
  const serviceUrl = this._getUrl(name, serviceGroup);
295
292
 
296
293
  return serviceUrl ? serviceUrl.get(priorityHost) : undefined;
@@ -301,7 +298,7 @@ const ServiceCatalog = AmpState.extend({
301
298
  *
302
299
  * @returns {Array<string>} - the current allowed domains list.
303
300
  */
304
- getAllowedDomains() {
301
+ getAllowedDomains(): Array<string> {
305
302
  return [...this.allowedDomains];
306
303
  },
307
304
 
@@ -338,17 +335,17 @@ const ServiceCatalog = AmpState.extend({
338
335
  /**
339
336
  * Mark a priority host service url as failed.
340
337
  * This will mark the host associated with the
341
- * `ServiceUrl` to be removed from the its
338
+ * `ServiceDetail` to be removed from the its
342
339
  * respective host array, and then return the next
343
- * viable host from the `ServiceUrls` host array,
344
- * or the `ServiceUrls` default url if no other priority
340
+ * viable host from the `ServiceDetail` host array,
341
+ * or the `ServiceDetail` default url if no other priority
345
342
  * hosts are available, or if `noPriorityHosts` is set to
346
343
  * `true`.
347
344
  * @param {string} url
348
345
  * @param {boolean} noPriorityHosts
349
346
  * @returns {string}
350
347
  */
351
- markFailedUrl(url, noPriorityHosts) {
348
+ markFailedUrl(url: string, noPriorityHosts = false): string | undefined {
352
349
  const serviceUrl = this._getUrl(
353
350
  Object.keys(this.list()).find((key) => this._getUrl(key).failHost(url))
354
351
  );
@@ -366,7 +363,7 @@ const ServiceCatalog = AmpState.extend({
366
363
  * @param {Array<string>} allowedDomains - allowed domains to be assigned.
367
364
  * @returns {void}
368
365
  */
369
- setAllowedDomains(allowedDomains) {
366
+ setAllowedDomains(allowedDomains: Array<string>): void {
370
367
  this.allowedDomains = [...allowedDomains];
371
368
  },
372
369
 
@@ -375,37 +372,36 @@ const ServiceCatalog = AmpState.extend({
375
372
  * @param {Array<string>} newAllowedDomains - new allowed domains to add to existing set of allowed domains
376
373
  * @returns {void}
377
374
  */
378
- addAllowedDomains(newAllowedDomains) {
375
+ addAllowedDomains(newAllowedDomains: Array<string>): void {
379
376
  this.allowedDomains = union(this.allowedDomains, newAllowedDomains);
380
377
  },
381
378
 
382
379
  /**
383
- * Update the current list of `ServiceUrl`s against a provided
380
+ * Update the current list of `ServiceDetail`s against a provided
384
381
  * service hostmap.
385
382
  * @emits ServiceCatalog#preauthorized
386
383
  * @emits ServiceCatalog#postauthorized
387
384
  * @param {string} serviceGroup
388
385
  * @param {object} serviceHostmap
389
- * @returns {Services}
386
+ * @returns {void}
390
387
  */
391
- updateServiceUrls(serviceGroup, serviceHostmap) {
388
+ updateServiceUrls(serviceGroup: string, serviceHostmap: Array<IServiceDetail>): void {
392
389
  const currentServiceUrls = this.serviceGroups[serviceGroup];
393
390
 
394
391
  const unusedUrls = currentServiceUrls.filter((serviceUrl) =>
395
- serviceHostmap.every((item) => item.name !== serviceUrl.name)
392
+ serviceHostmap.every((item) => item.serviceName !== serviceUrl.serviceName)
396
393
  );
397
394
 
398
395
  this._unloadServiceUrls(serviceGroup, unusedUrls);
399
396
 
400
397
  serviceHostmap.forEach((serviceObj) => {
401
- const service = this._getUrl(serviceObj.name, serviceGroup);
398
+ const service = this._getUrl(serviceObj.serviceName, serviceGroup);
402
399
 
403
400
  if (service) {
404
- service.defaultUrl = serviceObj.defaultUrl;
405
- service.hosts = serviceObj.hosts || [];
401
+ service.serviceUrls = serviceObj.serviceUrls || [];
406
402
  } else {
407
403
  this._loadServiceUrls(serviceGroup, [
408
- new ServiceUrl({
404
+ new ServiceDetail({
409
405
  ...serviceObj,
410
406
  }),
411
407
  ]);
@@ -414,8 +410,6 @@ const ServiceCatalog = AmpState.extend({
414
410
 
415
411
  this.status[serviceGroup].ready = true;
416
412
  this.trigger(serviceGroup);
417
-
418
- return this;
419
413
  },
420
414
 
421
415
  /**
@@ -426,7 +420,7 @@ const ServiceCatalog = AmpState.extend({
426
420
  * @returns {Promise<void>}
427
421
  */
428
422
  waitForCatalog(serviceGroup, timeout) {
429
- return new Promise((resolve, reject) => {
423
+ return new Promise<void>((resolve, reject) => {
430
424
  if (this.status[serviceGroup].ready) {
431
425
  resolve();
432
426
  }
@@ -0,0 +1,97 @@
1
+ import AmpState from 'ampersand-state';
2
+ import {ServiceUrl} from './types';
3
+
4
+ /**
5
+ * @class
6
+ */
7
+ const ServiceDetail = AmpState.extend({
8
+ namespace: 'ServiceDetail',
9
+
10
+ props: {
11
+ serviceUrls: ['array', false, () => []],
12
+ serviceName: ['string', true, undefined],
13
+ id: ['string', true, undefined],
14
+ },
15
+
16
+ /**
17
+ * Generate a host url based on the host
18
+ * uri provided.
19
+ * @param {ServiceUrl} serviceUrl
20
+ * @returns {string}
21
+ */
22
+ _generateHostUrl(serviceUrl: ServiceUrl): string {
23
+ const url = new URL(serviceUrl.baseUrl);
24
+
25
+ // setting url.hostname will not apply during Url.format(), set host via
26
+ // a string literal instead.
27
+ url.host = `${serviceUrl.host}${url.port ? `:${url.port}` : ''}`;
28
+
29
+ return url.href;
30
+ },
31
+
32
+ /**
33
+ * Get the current host url with the highest priority. This will only return a URL with a filtered host that has the
34
+ * `homeCluster` value set to `true`.
35
+ * @returns {string} - The priority host url.
36
+ */
37
+ _getPriorityHostUrl(): string {
38
+ // format of catalog ensures that array is sorted by highest priority
39
+ let priorityServiceUrl = this._searchForValidPriorityHost();
40
+
41
+ if (!priorityServiceUrl) {
42
+ this.serviceUrls = this.serviceUrls.map((serviceUrl) => {
43
+ serviceUrl.failed = false;
44
+
45
+ return serviceUrl;
46
+ });
47
+
48
+ priorityServiceUrl = this._searchForValidPriorityHost();
49
+ }
50
+
51
+ return priorityServiceUrl ? this._generateHostUrl(priorityServiceUrl) : '';
52
+ },
53
+
54
+ /**
55
+ * Searches for a valid service URL with a priority greater than 0 that has not failed.
56
+ * @returns {ServiceUrl | undefined} - The first valid service URL found, or undefined if none exist.
57
+ */
58
+ _searchForValidPriorityHost(): ServiceUrl | undefined {
59
+ return this.serviceUrls.find((serviceUrl) => serviceUrl.priority > 0 && !serviceUrl.failed);
60
+ },
61
+
62
+ /**
63
+ * Attempt to mark a host from this `ServiceDetail` as failed and return true
64
+ * if the provided url has a host that could be successfully marked as failed.
65
+ *
66
+ * @param {string} url
67
+ * @returns {boolean}
68
+ */
69
+ failHost(url: string): boolean {
70
+ const failedUrl = new URL(url);
71
+
72
+ const foundHost = this.serviceUrls.find((serviceUrl) => serviceUrl.host === failedUrl.host);
73
+
74
+ if (foundHost) {
75
+ foundHost.failed = true;
76
+ }
77
+
78
+ return foundHost !== undefined;
79
+ },
80
+
81
+ /**
82
+ * Generate a url using the host with the
83
+ * highest priority via host rendering.
84
+ *
85
+ * @returns {string} - The full service url.
86
+ */
87
+ get(): string {
88
+ // return empty string to indicate that no service url is available
89
+ if (!this.serviceUrls || this.serviceUrls.length === 0) {
90
+ return '';
91
+ }
92
+
93
+ return this._getPriorityHostUrl();
94
+ },
95
+ });
96
+
97
+ export default ServiceDetail;
@@ -189,7 +189,7 @@ const Services = WebexPlugin.extend({
189
189
  forceRefresh,
190
190
  })
191
191
  .then((serviceHostMap) => {
192
- catalog.updateServiceUrls(serviceGroup, serviceHostMap);
192
+ catalog.updateServiceGroups(serviceGroup, serviceHostMap);
193
193
  this.updateCredentialsConfig();
194
194
  catalog.status[serviceGroup].collecting = false;
195
195
  })
@@ -455,7 +455,7 @@ const Services = WebexPlugin.extend({
455
455
 
456
456
  const serviceHostMap = this._formatReceivedHostmap(hostMap);
457
457
 
458
- return catalog.updateServiceUrls(serviceGroup, serviceHostMap);
458
+ return catalog.updateServiceGroups(serviceGroup, serviceHostMap);
459
459
  },
460
460
 
461
461
  /**
@@ -662,6 +662,28 @@ const Services = WebexPlugin.extend({
662
662
  return uri;
663
663
  },
664
664
 
665
+ /**
666
+ * Formats a host map entry for use in service catalog.
667
+ *
668
+ * @param {Object} entry - The host map entry to format.
669
+ * @param {string} entry.serviceName - i.e. conversation, identity, etc.
670
+ * @param {string} entry.id - The unique identifier for the service, usually clusterId.
671
+ * @param {Array<IServiceDetail>} entry.serviceUrls - The group to which the service belongs.
672
+ * @returns {Object} - The formatted host map entry.
673
+ */
674
+ _formatHostMapEntry({id, serviceName, serviceUrls}) {
675
+ const formattedServiceUrls = serviceUrls.map((serviceUrl) => ({
676
+ host: new URL(serviceUrl.baseUrl).host,
677
+ ...serviceUrl,
678
+ }));
679
+
680
+ return {
681
+ id,
682
+ serviceName,
683
+ serviceUrls: formattedServiceUrls,
684
+ };
685
+ },
686
+
665
687
  /**
666
688
  * @private
667
689
  * Organize a received hostmap from a service
@@ -670,18 +692,7 @@ const Services = WebexPlugin.extend({
670
692
  * @returns {object}
671
693
  */
672
694
  _formatReceivedHostmap({services, activeServices}) {
673
- const formattedHostmap = services.map(({id, serviceName, serviceUrls}) => {
674
- const formattedServiceUrls = serviceUrls.map((serviceUrl) => ({
675
- host: new URL(serviceUrl.baseUrl).host,
676
- ...serviceUrl,
677
- }));
678
-
679
- return {
680
- id,
681
- serviceName,
682
- serviceUrls: formattedServiceUrls,
683
- };
684
- });
695
+ const formattedHostmap = services.map((service) => this._formatHostMapEntry(service));
685
696
  this._updateActiveServices(activeServices);
686
697
  this._updateServices(services);
687
698
 
@@ -850,24 +861,30 @@ const Services = WebexPlugin.extend({
850
861
  // Check for discovery services.
851
862
  if (services.discovery) {
852
863
  // Format the discovery configuration into an injectable array.
853
- const formattedDiscoveryServices = Object.keys(services.discovery).map((key) => ({
854
- name: key,
855
- defaultUrl: services.discovery[key],
856
- }));
864
+ const formattedDiscoveryServices = Object.keys(services.discovery).map((key) =>
865
+ this._formatHostMapEntry({
866
+ id: key,
867
+ serviceName: key,
868
+ serviceUrls: [{baseUrl: services.discovery[key], priority: 1}],
869
+ })
870
+ );
857
871
 
858
872
  // Inject formatted discovery services into services catalog.
859
- catalog.updateServiceUrls('discovery', formattedDiscoveryServices);
873
+ catalog.updateServiceGroups('discovery', formattedDiscoveryServices);
860
874
  }
861
875
 
862
876
  if (services.override) {
863
877
  // Format the override configuration into an injectable array.
864
- const formattedOverrideServices = Object.keys(services.override).map((key) => ({
865
- name: key,
866
- defaultUrl: services.override[key],
867
- }));
878
+ const formattedOverrideServices = Object.keys(services.override).map((key) =>
879
+ this._formatHostMapEntry({
880
+ id: key,
881
+ serviceName: key,
882
+ serviceUrls: [{baseUrl: services.override[key], priority: 1}],
883
+ })
884
+ );
868
885
 
869
886
  // Inject formatted override services into services catalog.
870
- catalog.updateServiceUrls('override', formattedOverrideServices);
887
+ catalog.updateServiceGroups('override', formattedOverrideServices);
871
888
  }
872
889
 
873
890
  // if not fedramp, append on the commercialAllowedDomains
@@ -0,0 +1,12 @@
1
+ export type ServiceUrl = {
2
+ baseUrl: string;
3
+ host: string;
4
+ priority: number;
5
+ failed?: boolean;
6
+ };
7
+
8
+ export interface IServiceDetail {
9
+ id: string;
10
+ serviceName: string;
11
+ serviceUrls: Array<ServiceUrl>;
12
+ }
@@ -120,23 +120,25 @@ export const serviceHostmapV2 = {
120
120
  format: 'U2Cv2',
121
121
  };
122
122
 
123
+ export const formattedServiceHostmapEntryConv = {
124
+ id: 'urn:TEAM:us-east-2_a:conversation',
125
+ serviceName: 'conversation',
126
+ serviceUrls: [
127
+ {
128
+ baseUrl: 'https://prod-achm-message.svc.webex.com/conversation/api/v1',
129
+ host: 'prod-achm-message.svc.webex.com',
130
+ priority: 1,
131
+ },
132
+ {
133
+ baseUrl: 'https://conv-a.wbx2.com/conversation/api/v1',
134
+ host: 'conv-a.wbx2.com',
135
+ priority: 2,
136
+ },
137
+ ],
138
+ };
139
+
123
140
  export const formattedServiceHostmapV2 = [
124
- {
125
- id: 'urn:TEAM:us-east-2_a:conversation',
126
- serviceName: 'conversation',
127
- serviceUrls: [
128
- {
129
- baseUrl: 'https://prod-achm-message.svc.webex.com/conversation/api/v1',
130
- host: 'prod-achm-message.svc.webex.com',
131
- priority: 1,
132
- },
133
- {
134
- baseUrl: 'https://conv-a.wbx2.com/conversation/api/v1',
135
- host: 'conv-a.wbx2.com',
136
- priority: 2,
137
- },
138
- ],
139
- },
141
+ formattedServiceHostmapEntryConv,
140
142
  {
141
143
  id: 'urn:TEAM:me-central-1_d:conversation',
142
144
  serviceName: 'conversation',
@@ -0,0 +1,147 @@
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {assert} from '@webex/test-helper-chai';
6
+ import MockWebex from '@webex/test-helper-mock-webex';
7
+ import {ServicesV2, ServiceDetail} from '@webex/webex-core';
8
+ import {formattedServiceHostmapEntryConv} from '../../../fixtures/host-catalog-v2';
9
+
10
+ describe('webex-core', () => {
11
+ describe('ServiceDetail', () => {
12
+ let webex;
13
+ let serviceDetail;
14
+ let template;
15
+
16
+ beforeEach(() => {
17
+ webex = new MockWebex();
18
+ new ServicesV2(undefined, {parent: webex});
19
+
20
+ template = formattedServiceHostmapEntryConv;
21
+
22
+ serviceDetail = new ServiceDetail({...template});
23
+ });
24
+
25
+ describe('#namespace', () => {
26
+ it('is accurate to plugin name', () => {
27
+ assert.equal(serviceDetail.namespace, 'ServiceDetail');
28
+ });
29
+ });
30
+
31
+ describe('#serviceName', () => {
32
+ it('is valid value', () => {
33
+ assert.typeOf(serviceDetail.serviceName, 'string');
34
+ assert.equal(serviceDetail.serviceName, 'conversation');
35
+ });
36
+ });
37
+
38
+ describe('#serviceUrls', () => {
39
+ it('is valid value', () => {
40
+ assert.typeOf(serviceDetail.serviceUrls, 'array');
41
+ });
42
+
43
+ it('contains all appended hosts on construction', () => {
44
+ template.serviceUrls.forEach((serviceUrl) => {
45
+ assert.include([...serviceDetail.serviceUrls], serviceUrl);
46
+ });
47
+ });
48
+ });
49
+
50
+ describe('#id', () => {
51
+ it('is valid value', () => {
52
+ assert.typeOf(serviceDetail.id, 'string');
53
+ assert.equal(serviceDetail.id, 'urn:TEAM:us-east-2_a:conversation');
54
+ });
55
+ });
56
+
57
+ describe('#_generateHostUrl()', () => {
58
+ it('returns a string', () => {
59
+ serviceDetail.serviceUrls.forEach((serviceUrl) => {
60
+ assert.typeOf(serviceDetail._generateHostUrl(serviceUrl), 'string');
61
+ });
62
+ });
63
+
64
+ it('replaces the host of a pass in url', () => {
65
+ serviceDetail.serviceUrls.forEach((serviceUrl) => {
66
+ assert.equal(
67
+ serviceDetail._generateHostUrl(serviceUrl),
68
+ `https://${serviceUrl.host}/conversation/api/v1`
69
+ );
70
+ });
71
+ });
72
+ });
73
+
74
+ describe('#_getPriorityHostUrl()', () => {
75
+ it('validates that the retrieved high priority host matches the manually retrieved high priority host', () => {
76
+ assert.equal(
77
+ serviceDetail._getPriorityHostUrl(),
78
+ serviceDetail._generateHostUrl(template.serviceUrls[0])
79
+ );
80
+ });
81
+
82
+ it('should pick most priority non failed host', () => {
83
+ serviceDetail.serviceUrls[0].failed = true;
84
+
85
+ assert.isTrue(serviceDetail.serviceUrls[0].failed);
86
+
87
+ const priorityHost = serviceDetail._getPriorityHostUrl();
88
+ assert.equal(priorityHost, serviceDetail.serviceUrls[1].baseUrl);
89
+ });
90
+
91
+ it('should reset the hosts when all have failed', () => {
92
+ serviceDetail.serviceUrls.forEach((serviceUrl) => {
93
+ /* eslint-disable-next-line no-param-reassign */
94
+ serviceUrl.failed = true;
95
+ });
96
+
97
+ assert.isTrue(serviceDetail.serviceUrls.every((serviceUrl) => serviceUrl.failed));
98
+
99
+ const priorityHost = serviceDetail._getPriorityHostUrl();
100
+
101
+ assert.equal(priorityHost, serviceDetail.serviceUrls[0].baseUrl);
102
+ assert.isTrue(serviceDetail.serviceUrls.every((serviceUrl) => !serviceUrl.failed));
103
+ });
104
+ it('should return empty string if no available hosts', () => {
105
+ serviceDetail.serviceUrls = [{priority: -1}];
106
+
107
+ const priorityHost = serviceDetail.get();
108
+
109
+ assert.equal(priorityHost, '');
110
+ });
111
+ });
112
+
113
+ describe('#get', () => {
114
+ it('should return empty string if no hosts are available', () => {
115
+ serviceDetail.serviceUrls = [];
116
+
117
+ const priorityHost = serviceDetail.get();
118
+
119
+ assert.equal(priorityHost, '');
120
+ });
121
+ });
122
+
123
+ describe('#failHost()', () => {
124
+ it('marks a host as failed', () => {
125
+ serviceDetail.failHost(serviceDetail.serviceUrls[0].baseUrl);
126
+
127
+ const removedHost = serviceDetail.serviceUrls.find(
128
+ (currentHost) => currentHost.host === serviceDetail.serviceUrls[0].host
129
+ );
130
+
131
+ assert.isTrue(removedHost.failed);
132
+ });
133
+
134
+ it('returns true if hostUrl was found', () => {
135
+ const removedHostResult = serviceDetail.failHost(serviceDetail.serviceUrls[0].baseUrl);
136
+
137
+ assert.isTrue(removedHostResult);
138
+ });
139
+
140
+ it('returns false if hostUrl was not found', () => {
141
+ const removedHostResult = serviceDetail.failHost('https://someurl.com/api/vq');
142
+
143
+ assert.isFalse(removedHostResult);
144
+ });
145
+ });
146
+ });
147
+ });