@webex/webex-core 3.8.0 → 3.8.1-next.1

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 (54) hide show
  1. package/dist/index.js +43 -0
  2. package/dist/index.js.map +1 -1
  3. package/dist/interceptors/redirect.js +18 -0
  4. package/dist/interceptors/redirect.js.map +1 -1
  5. package/dist/lib/batcher.js +1 -1
  6. package/dist/lib/credentials/credentials.js +1 -1
  7. package/dist/lib/credentials/token.js +1 -1
  8. package/dist/lib/services/services.js +1 -1
  9. package/dist/lib/services-v2/constants.js +17 -0
  10. package/dist/lib/services-v2/constants.js.map +1 -0
  11. package/dist/lib/services-v2/index.js +58 -0
  12. package/dist/lib/services-v2/index.js.map +1 -0
  13. package/dist/lib/services-v2/interceptors/hostmap.js +64 -0
  14. package/dist/lib/services-v2/interceptors/hostmap.js.map +1 -0
  15. package/dist/lib/services-v2/interceptors/server-error.js +77 -0
  16. package/dist/lib/services-v2/interceptors/server-error.js.map +1 -0
  17. package/dist/lib/services-v2/interceptors/service.js +137 -0
  18. package/dist/lib/services-v2/interceptors/service.js.map +1 -0
  19. package/dist/lib/services-v2/metrics.js +12 -0
  20. package/dist/lib/services-v2/metrics.js.map +1 -0
  21. package/dist/lib/services-v2/service-catalog.js +346 -0
  22. package/dist/lib/services-v2/service-catalog.js.map +1 -0
  23. package/dist/lib/services-v2/service-detail.js +94 -0
  24. package/dist/lib/services-v2/service-detail.js.map +1 -0
  25. package/dist/lib/services-v2/service-fed-ramp.js +13 -0
  26. package/dist/lib/services-v2/service-fed-ramp.js.map +1 -0
  27. package/dist/lib/services-v2/services-v2.js +985 -0
  28. package/dist/lib/services-v2/services-v2.js.map +1 -0
  29. package/dist/lib/services-v2/types.js +7 -0
  30. package/dist/lib/services-v2/types.js.map +1 -0
  31. package/dist/plugins/logger.js +1 -1
  32. package/dist/webex-core.js +2 -2
  33. package/dist/webex-core.js.map +1 -1
  34. package/package.json +13 -13
  35. package/src/index.js +10 -0
  36. package/src/interceptors/redirect.js +28 -0
  37. package/src/lib/services-v2/README.md +3 -0
  38. package/src/lib/services-v2/constants.ts +21 -0
  39. package/src/lib/services-v2/index.ts +23 -0
  40. package/src/lib/services-v2/interceptors/hostmap.js +36 -0
  41. package/src/lib/services-v2/interceptors/server-error.js +48 -0
  42. package/src/lib/services-v2/interceptors/service.js +101 -0
  43. package/src/lib/services-v2/metrics.js +4 -0
  44. package/src/lib/services-v2/service-catalog.ts +360 -0
  45. package/src/lib/services-v2/service-detail.ts +97 -0
  46. package/src/lib/services-v2/service-fed-ramp.ts +5 -0
  47. package/src/lib/services-v2/services-v2.js +988 -0
  48. package/src/lib/services-v2/types.ts +13 -0
  49. package/test/fixtures/host-catalog-v2.ts +249 -0
  50. package/test/integration/spec/services/services.js +12 -10
  51. package/test/unit/spec/interceptors/redirect.js +72 -0
  52. package/test/unit/spec/services-v2/service-catalog.ts +288 -0
  53. package/test/unit/spec/services-v2/service-detail.ts +147 -0
  54. package/test/unit/spec/services-v2/services-v2.ts +562 -0
@@ -0,0 +1,13 @@
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
+ failHost(url: string): boolean;
13
+ }
@@ -0,0 +1,249 @@
1
+ export const serviceHostmapV2 = {
2
+ activeServices: {
3
+ conversation: 'urn:TEAM:us-east-2_a:conversation',
4
+ idbroker: 'urn:TEAM:us-east-2_a:idbroker',
5
+ locus: 'urn:TEAM:us-east-2_a:locus',
6
+ mercury: 'urn:TEAM:us-east-2_a:mercury',
7
+ },
8
+ services: [
9
+ {
10
+ id: 'urn:TEAM:us-east-2_a:conversation',
11
+ serviceName: 'conversation',
12
+ serviceUrls: [
13
+ {
14
+ baseUrl: 'https://prod-achm-message.svc.webex.com/conversation/api/v1',
15
+ priority: 1,
16
+ },
17
+ {
18
+ baseUrl: 'https://conv-a.wbx2.com/conversation/api/v1',
19
+ priority: 2,
20
+ },
21
+ ],
22
+ },
23
+ {
24
+ id: 'urn:TEAM:me-central-1_d:conversation',
25
+ serviceName: 'conversation',
26
+ serviceUrls: [
27
+ {
28
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/conversation/api/v1',
29
+ priority: 1,
30
+ },
31
+ {
32
+ baseUrl: 'https://conv-d.wbx2.com/conversation/api/v1',
33
+ priority: 2,
34
+ },
35
+ ],
36
+ },
37
+ {
38
+ id: 'urn:TEAM:us-east-2_a:idbroker',
39
+ serviceName: 'idbroker',
40
+ serviceUrls: [
41
+ {
42
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/idbroker/api/v1',
43
+ priority: 1,
44
+ },
45
+ {
46
+ baseUrl: 'https://idbroker.webex.com/idb/api/v1',
47
+ priority: 2,
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ id: 'urn:TEAM:me-central-1_d:idbroker',
53
+ serviceName: 'idbroker',
54
+ serviceUrls: [
55
+ {
56
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/idbroker/api/v1',
57
+ priority: 1,
58
+ },
59
+ {
60
+ baseUrl: 'https://conv-d.wbx2.com/idbroker/api/v1',
61
+ priority: 2,
62
+ },
63
+ ],
64
+ },
65
+ {
66
+ id: 'urn:TEAM:us-east-2_a:locus',
67
+ serviceName: 'locus',
68
+ serviceUrls: [
69
+ {
70
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/locus/api/v1',
71
+ priority: 1,
72
+ },
73
+ {
74
+ baseUrl: 'https://locus-a.wbx2.com/locus/api/v1',
75
+ priority: 2,
76
+ },
77
+ ],
78
+ },
79
+ {
80
+ id: 'urn:TEAM:me-central-1_d:locus',
81
+ serviceName: 'locus',
82
+ serviceUrls: [
83
+ {
84
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/locus/api/v1',
85
+ priority: 1,
86
+ },
87
+ {
88
+ baseUrl: 'https://conv-d.wbx2.com/locus/api/v1',
89
+ priority: 2,
90
+ },
91
+ ],
92
+ },
93
+ {
94
+ id: 'urn:TEAM:us-east-2_a:mercury',
95
+ serviceName: 'mercury',
96
+ serviceUrls: [
97
+ {
98
+ baseUrl: 'https://mercury-a.wbx2.com/mercury/api/v1',
99
+ priority: 1,
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ id: 'urn:TEAM:me-central-1_d:mercury',
105
+ serviceName: 'mercury',
106
+ serviceUrls: [
107
+ {
108
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/mercury/api/v1',
109
+ priority: 1,
110
+ },
111
+ {
112
+ baseUrl: 'https://conv-d.wbx2.com/mercury/api/v1',
113
+ priority: 2,
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ orgId: '3e0e410f-f83f-4ee4-ac32-12692e99355c',
119
+ timestamp: '1745533341',
120
+ format: 'U2Cv2',
121
+ };
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
+
140
+ export const formattedServiceHostmapV2 = [
141
+ formattedServiceHostmapEntryConv,
142
+ {
143
+ id: 'urn:TEAM:me-central-1_d:conversation',
144
+ serviceName: 'conversation',
145
+ serviceUrls: [
146
+ {
147
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/conversation/api/v1',
148
+ host: 'prod-adxb-message.svc.webex.com',
149
+ priority: 1,
150
+ },
151
+ {
152
+ baseUrl: 'https://conv-d.wbx2.com/conversation/api/v1',
153
+ host: 'conv-d.wbx2.com',
154
+ priority: 2,
155
+ },
156
+ ],
157
+ },
158
+ {
159
+ id: 'urn:TEAM:us-east-2_a:idbroker',
160
+ serviceName: 'idbroker',
161
+ serviceUrls: [
162
+ {
163
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/idbroker/api/v1',
164
+ host: 'prod-adxb-message.svc.webex.com',
165
+ priority: 1,
166
+ },
167
+ {
168
+ baseUrl: 'https://idbroker.webex.com/idb/api/v1',
169
+ host: 'idbroker.webex.com',
170
+ priority: 2,
171
+ },
172
+ ],
173
+ },
174
+ {
175
+ id: 'urn:TEAM:me-central-1_d:idbroker',
176
+ serviceName: 'idbroker',
177
+ serviceUrls: [
178
+ {
179
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/idbroker/api/v1',
180
+ host: 'prod-adxb-message.svc.webex.com',
181
+ priority: 1,
182
+ },
183
+ {
184
+ baseUrl: 'https://conv-d.wbx2.com/idbroker/api/v1',
185
+ host: 'conv-d.wbx2.com',
186
+ priority: 2,
187
+ },
188
+ ],
189
+ },
190
+ {
191
+ id: 'urn:TEAM:us-east-2_a:locus',
192
+ serviceName: 'locus',
193
+ serviceUrls: [
194
+ {
195
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/locus/api/v1',
196
+ host: 'prod-adxb-message.svc.webex.com',
197
+ priority: 1,
198
+ },
199
+ {
200
+ baseUrl: 'https://locus-a.wbx2.com/locus/api/v1',
201
+ host: 'locus-a.wbx2.com',
202
+ priority: 2,
203
+ },
204
+ ],
205
+ },
206
+ {
207
+ id: 'urn:TEAM:me-central-1_d:locus',
208
+ serviceName: 'locus',
209
+ serviceUrls: [
210
+ {
211
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/locus/api/v1',
212
+ host: 'prod-adxb-message.svc.webex.com',
213
+ priority: 1,
214
+ },
215
+ {
216
+ baseUrl: 'https://conv-d.wbx2.com/locus/api/v1',
217
+ host: 'conv-d.wbx2.com',
218
+ priority: 2,
219
+ },
220
+ ],
221
+ },
222
+ {
223
+ id: 'urn:TEAM:us-east-2_a:mercury',
224
+ serviceName: 'mercury',
225
+ serviceUrls: [
226
+ {
227
+ baseUrl: 'https://mercury-a.wbx2.com/mercury/api/v1',
228
+ host: 'mercury-a.wbx2.com',
229
+ priority: 1,
230
+ },
231
+ ],
232
+ },
233
+ {
234
+ id: 'urn:TEAM:me-central-1_d:mercury',
235
+ serviceName: 'mercury',
236
+ serviceUrls: [
237
+ {
238
+ baseUrl: 'https://prod-adxb-message.svc.webex.com/mercury/api/v1',
239
+ host: 'prod-adxb-message.svc.webex.com',
240
+ priority: 1,
241
+ },
242
+ {
243
+ baseUrl: 'https://conv-d.wbx2.com/mercury/api/v1',
244
+ host: 'conv-d.wbx2.com',
245
+ priority: 2,
246
+ },
247
+ ],
248
+ },
249
+ ];
@@ -37,15 +37,17 @@ describe('webex-core', () => {
37
37
  orgId: process.env.EU_PRIMARY_ORG_ID,
38
38
  },
39
39
  }),
40
- ]).then(([[user], [userEU]]) =>
41
- new Promise((resolve) => {
42
- setTimeout(() => {
43
- webexUser = user;
44
- webexUserEU = userEU;
45
- resolve();
46
- }, 1000)
47
- })
48
- ));
40
+ ]).then(
41
+ ([[user], [userEU]]) =>
42
+ new Promise((resolve) => {
43
+ setTimeout(() => {
44
+ webexUser = user;
45
+ webexUserEU = userEU;
46
+ resolve();
47
+ }, 1000);
48
+ })
49
+ )
50
+ );
49
51
 
50
52
  beforeEach('create webex instance', () => {
51
53
  webex = new WebexCore({credentials: {supertoken: webexUser.token}});
@@ -893,7 +895,7 @@ describe('webex-core', () => {
893
895
  assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
894
896
  }));
895
897
 
896
- it('validates new user with activationOptions suppressEmail true', () =>
898
+ it.skip('validates new user with activationOptions suppressEmail true', () =>
897
899
  unauthServices
898
900
  .validateUser({
899
901
  email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
@@ -96,6 +96,78 @@ describe('webex-core', () => {
96
96
 
97
97
  assert.equal(interceptor.onResponse({$redirectCount: 5}, response), response);
98
98
  });
99
+
100
+ it('redirects GET requests to new url on appapi redirect error', () => {
101
+ const response = {
102
+ statusCode: 404,
103
+ headers: {},
104
+ body: {
105
+ code: 404100,
106
+ data: {
107
+ siteFullUrl: 'newlocus.example.com'
108
+ },
109
+ },
110
+ };
111
+
112
+ interceptor.onResponse({$redirectCount: 0, uri: 'https://test.webex.com/meet/v1/join'}, response);
113
+ sinon.assert.calledWith(webex.request, {
114
+ $redirectCount: 1,
115
+ uri: 'https://newlocus.example.com/meet/v1/join',
116
+ });
117
+ });
118
+ it('returns when appapi redirect is not encountered', () => {
119
+ const response = {
120
+ statusCode: 404,
121
+ headers: {},
122
+ body: {
123
+ code: 404101,
124
+ data: {
125
+ siteFullUrl: 'http://newlocus.example.com?alternate=true'
126
+ },
127
+ },
128
+ };
129
+
130
+ assert.equal(interceptor.onResponse({$redirectCount: 5}, response), response);
131
+ });
132
+ it('does not redirect on reaching max redirects', () => {
133
+ const response = {
134
+ statusCode: 404,
135
+ headers: {},
136
+ body: {
137
+ code: 404100,
138
+ data: {
139
+ siteFullUrl: 'http://newlocus.example.com?alternate=true'
140
+ },
141
+ },
142
+ options: {
143
+ qs: true,
144
+ },
145
+ };
146
+
147
+ assert.isRejected(interceptor.onResponse({$redirectCount: 5}, response));
148
+ });
149
+
150
+ it('redirects POST requests to new url on appapi redirect error', () => {
151
+ const response = {
152
+ statusCode: 404,
153
+ headers: {},
154
+ body: {
155
+ code: 404100,
156
+ data: {
157
+ siteFullUrl: 'http://newlocus.example.com?alternate=true'
158
+ },
159
+ },
160
+ options: {
161
+ qs: true,
162
+ },
163
+ };
164
+
165
+ interceptor.onResponse({$redirectCount: 4}, response);
166
+ sinon.assert.calledWith(webex.request, {
167
+ $redirectCount: 5,
168
+ uri: 'http://newlocus.example.com',
169
+ });
170
+ });
99
171
  });
100
172
  });
101
173
  });
@@ -0,0 +1,288 @@
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} from '@webex/webex-core';
8
+ import {formattedServiceHostmapV2} from '../../../fixtures/host-catalog-v2';
9
+
10
+ describe('webex-core', () => {
11
+ describe('ServiceCatalogV2', () => {
12
+ let webex;
13
+ let services;
14
+ let catalog;
15
+
16
+ beforeEach(() => {
17
+ webex = new MockWebex();
18
+ services = new ServicesV2(undefined, {parent: webex});
19
+ catalog = services._getCatalog();
20
+ });
21
+
22
+ describe('#namespace', () => {
23
+ it('is accurate to plugin name', () => {
24
+ assert.equal(catalog.namespace, 'ServiceCatalog');
25
+ });
26
+ });
27
+
28
+ describe('#serviceGroups', () => {
29
+ it('has all the required keys', () => {
30
+ assert.hasAllKeys(catalog.serviceGroups, [
31
+ 'discovery',
32
+ 'override',
33
+ 'preauth',
34
+ 'signin',
35
+ 'postauth',
36
+ ]);
37
+ });
38
+
39
+ it('contains values that are arrays', () => {
40
+ Object.keys(catalog.serviceGroups).forEach((key) => {
41
+ assert.typeOf(catalog.serviceGroups[key], 'array');
42
+ });
43
+ });
44
+ });
45
+
46
+ describe('#status', () => {
47
+ it('has all the required keys', () => {
48
+ assert.hasAllKeys(catalog.status, [
49
+ 'discovery',
50
+ 'override',
51
+ 'preauth',
52
+ 'postauth',
53
+ 'signin',
54
+ ]);
55
+ });
56
+
57
+ it('has valid key value types', () => {
58
+ assert.typeOf(catalog.status.preauth.ready, 'boolean');
59
+ assert.typeOf(catalog.status.preauth.collecting, 'boolean');
60
+ assert.typeOf(catalog.status.postauth.ready, 'boolean');
61
+ assert.typeOf(catalog.status.postauth.collecting, 'boolean');
62
+ assert.typeOf(catalog.status.signin.ready, 'boolean');
63
+ assert.typeOf(catalog.status.signin.collecting, 'boolean');
64
+ });
65
+ });
66
+
67
+ describe('#allowedDomains', () => {
68
+ it('is an array', () => {
69
+ assert.isArray(catalog.allowedDomains);
70
+ });
71
+ });
72
+
73
+ describe('#clean()', () => {
74
+ beforeEach(() => {
75
+ catalog.serviceGroups.preauth = [1, 2, 3];
76
+ catalog.serviceGroups.signin = [1, 2, 3];
77
+ catalog.serviceGroups.postauth = [1, 2, 3];
78
+ catalog.status.preauth = {ready: true};
79
+ catalog.status.signin = {ready: true};
80
+ catalog.status.postauth = {ready: true};
81
+ });
82
+
83
+ it('should reset service group ready status', () => {
84
+ catalog.clean();
85
+
86
+ assert.isFalse(catalog.status.preauth.ready);
87
+ assert.isFalse(catalog.status.signin.ready);
88
+ assert.isFalse(catalog.status.postauth.ready);
89
+ });
90
+
91
+ it('should clear all collected service groups', () => {
92
+ catalog.clean();
93
+
94
+ assert.equal(catalog.serviceGroups.preauth.length, 0);
95
+ assert.equal(catalog.serviceGroups.signin.length, 0);
96
+ assert.equal(catalog.serviceGroups.postauth.length, 0);
97
+ });
98
+ });
99
+
100
+ describe('#findAllowedDomain()', () => {
101
+ const domains = [];
102
+
103
+ beforeEach(() => {
104
+ domains.push('example-a', 'example-b', 'example-c');
105
+
106
+ catalog.setAllowedDomains(domains);
107
+ });
108
+
109
+ afterEach(() => {
110
+ domains.length = 0;
111
+ });
112
+
113
+ it('finds an allowed domain that matches a specific url', () => {
114
+ const domain = catalog.findAllowedDomain('http://example-a.com/resource/id');
115
+
116
+ assert.include(domains, domain);
117
+ });
118
+ });
119
+
120
+ describe('#getAllowedDomains()', () => {
121
+ const domains = [];
122
+
123
+ beforeEach(() => {
124
+ domains.push('example-a', 'example-b', 'example-c');
125
+
126
+ catalog.setAllowedDomains(domains);
127
+ });
128
+
129
+ afterEach(() => {
130
+ domains.length = 0;
131
+ });
132
+
133
+ it('returns a an array of allowed hosts', () => {
134
+ const list = catalog.getAllowedDomains();
135
+
136
+ assert.match(domains, list);
137
+ });
138
+ });
139
+
140
+ describe('#setAllowedDomains()', () => {
141
+ const domains = [];
142
+
143
+ beforeEach(() => {
144
+ domains.push('example-a', 'example-b', 'example-c');
145
+
146
+ catalog.setAllowedDomains(domains);
147
+ });
148
+
149
+ afterEach(() => {
150
+ domains.length = 0;
151
+ });
152
+
153
+ it('sets the allowed domain entries to new values', () => {
154
+ const newValues = ['example-d', 'example-e', 'example-f'];
155
+
156
+ catalog.setAllowedDomains(newValues);
157
+
158
+ assert.notDeepInclude(domains, newValues);
159
+ });
160
+ });
161
+
162
+ describe('#addAllowedDomains()', () => {
163
+ const domains = [];
164
+
165
+ beforeEach(() => {
166
+ domains.push('example-a', 'example-b', 'example-c');
167
+
168
+ catalog.setAllowedDomains(domains);
169
+ });
170
+
171
+ afterEach(() => {
172
+ domains.length = 0;
173
+ });
174
+
175
+ it('merge the allowed domain entries with new values', () => {
176
+ const newValues = ['example-c', 'example-e', 'example-f'];
177
+
178
+ catalog.addAllowedDomains(newValues);
179
+
180
+ const list = catalog.getAllowedDomains();
181
+
182
+ assert.match(['example-a', 'example-b', 'example-c', 'example-e', 'example-f'], list);
183
+ });
184
+ });
185
+
186
+ describe('#markFailedServiceUrl()', () => {
187
+ afterEach(() => {
188
+ catalog._getServiceDetail('urn:TEAM:us-east-2_a:conversation').serviceUrls[0].failed =
189
+ false;
190
+ });
191
+
192
+ it('marks service url failed, and retrieves next highest priority', () => {
193
+ catalog.updateServiceGroups('postauth', formattedServiceHostmapV2);
194
+
195
+ const currentHighest = catalog._getServiceDetail('urn:TEAM:us-east-2_a:conversation').get();
196
+
197
+ assert.equal(currentHighest, 'https://prod-achm-message.svc.webex.com/conversation/api/v1');
198
+
199
+ const nextHighest = catalog.markFailedServiceUrl(
200
+ 'https://prod-achm-message.svc.webex.com/conversation/api/v1'
201
+ );
202
+
203
+ assert.equal(nextHighest, 'https://conv-a.wbx2.com/conversation/api/v1');
204
+ });
205
+
206
+ it('returns undefined if url does not exist', () => {
207
+ catalog.updateServiceGroups('postauth', formattedServiceHostmapV2);
208
+
209
+ const currentHighest = catalog._getServiceDetail('urn:TEAM:us-east-2_a:conversation').get();
210
+
211
+ assert.equal(currentHighest, 'https://prod-achm-message.svc.webex.com/conversation/api/v1');
212
+
213
+ const nextHighest = catalog.markFailedServiceUrl(
214
+ 'https://doesnotexist.com/conversation/api/v1'
215
+ );
216
+
217
+ assert.equal(nextHighest, undefined);
218
+ });
219
+
220
+ it('returns original highest priority url if all urls in service were already marked as failure', () => {
221
+ catalog.updateServiceGroups('postauth', formattedServiceHostmapV2);
222
+
223
+ const currentHighest = catalog._getServiceDetail('urn:TEAM:us-east-2_a:conversation').get();
224
+
225
+ assert.equal(currentHighest, 'https://prod-achm-message.svc.webex.com/conversation/api/v1');
226
+
227
+ catalog
228
+ ._getServiceDetail('urn:TEAM:us-east-2_a:conversation')
229
+ .serviceUrls.forEach((url) => (url.failed = true));
230
+
231
+ const nextHighest = catalog.markFailedServiceUrl(
232
+ 'https://prod-achm-message.svc.webex.com/conversation/api/v1'
233
+ );
234
+
235
+ assert.equal(nextHighest, 'https://prod-achm-message.svc.webex.com/conversation/api/v1');
236
+ });
237
+ });
238
+
239
+ describe('findServiceDetailFromUrl()', () => {
240
+ const otherService = {
241
+ serviceUrls: [
242
+ {baseUrl: 'https://example.com/differentresource'},
243
+ {baseUrl: 'https://example.com/differentresource'},
244
+ ],
245
+ };
246
+
247
+ it.each(['discovery', 'preauth', 'signin', 'postauth', 'override'])(
248
+ 'matches a default url correctly',
249
+ (serviceGroup) => {
250
+ const url = 'https://example.com/resource/id';
251
+
252
+ const exampleService = {
253
+ serviceUrls: [
254
+ {baseUrl: 'https://example.com/resource'},
255
+ {baseUrl: 'https://example2.com/resource'},
256
+ ],
257
+ };
258
+
259
+ catalog.serviceGroups[serviceGroup].push(otherService, exampleService);
260
+
261
+ const service = catalog.findServiceDetailFromUrl(url);
262
+
263
+ assert.equal(service, exampleService);
264
+ }
265
+ );
266
+
267
+ it.each(['discovery', 'preauth', 'signin', 'postauth', 'override'])(
268
+ 'matches an alternate host url',
269
+ (serviceGroup) => {
270
+ const url = 'https://example2.com/resource/id';
271
+
272
+ const exampleService = {
273
+ serviceUrls: [
274
+ {baseUrl: 'https://example.com/resource'},
275
+ {baseUrl: 'https://example2.com/resource'},
276
+ ],
277
+ };
278
+
279
+ catalog.serviceGroups[serviceGroup].push(otherService, exampleService);
280
+
281
+ const service = catalog.findServiceDetailFromUrl(url);
282
+
283
+ assert.equal(service, exampleService);
284
+ }
285
+ );
286
+ });
287
+ });
288
+ });