@itentialopensource/adapter-openstack_cinder 0.1.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 (130) hide show
  1. package/.eslintignore +5 -0
  2. package/.eslintrc.js +18 -0
  3. package/.jshintrc +3 -0
  4. package/AUTH.md +43 -0
  5. package/BROKER.md +199 -0
  6. package/CALLS.md +1118 -0
  7. package/CHANGELOG.md +9 -0
  8. package/CODE_OF_CONDUCT.md +43 -0
  9. package/CONTRIBUTING.md +172 -0
  10. package/ENHANCE.md +69 -0
  11. package/LICENSE +201 -0
  12. package/PROPERTIES.md +641 -0
  13. package/README.md +337 -0
  14. package/SUMMARY.md +9 -0
  15. package/SYSTEMINFO.md +11 -0
  16. package/TROUBLESHOOT.md +47 -0
  17. package/adapter.js +20288 -0
  18. package/adapterBase.js +1788 -0
  19. package/entities/.generic/action.json +214 -0
  20. package/entities/.generic/schema.json +28 -0
  21. package/entities/.system/action.json +50 -0
  22. package/entities/.system/mockdatafiles/getToken-default.json +242 -0
  23. package/entities/.system/mockdatafiles/healthcheck-default.json +3 -0
  24. package/entities/.system/schema.json +19 -0
  25. package/entities/.system/schemaTokenReq.json +53 -0
  26. package/entities/.system/schemaTokenResp.json +49 -0
  27. package/entities/APIExtensionsExtensions/action.json +25 -0
  28. package/entities/APIExtensionsExtensions/schema.json +30 -0
  29. package/entities/APIVersionDetails/action.json +25 -0
  30. package/entities/APIVersionDetails/schema.json +19 -0
  31. package/entities/APIVersions/action.json +25 -0
  32. package/entities/APIVersions/schema.json +19 -0
  33. package/entities/AttachmentsAttachments/action.json +147 -0
  34. package/entities/AttachmentsAttachments/schema.json +58 -0
  35. package/entities/BackEndStoragePools/action.json +25 -0
  36. package/entities/BackEndStoragePools/schema.json +30 -0
  37. package/entities/BackupActionsBackupsAction/action.json +24 -0
  38. package/entities/BackupActionsBackupsAction/schema.json +41 -0
  39. package/entities/BackupsBackups/action.json +188 -0
  40. package/entities/BackupsBackups/schema.json +71 -0
  41. package/entities/CapabilitiesForStorageBackEndsCapabilities/action.json +25 -0
  42. package/entities/CapabilitiesForStorageBackEndsCapabilities/schema.json +30 -0
  43. package/entities/ConsistencyGroupSnapshotsDEPRECATED/action.json +107 -0
  44. package/entities/ConsistencyGroupSnapshotsDEPRECATED/schema.json +56 -0
  45. package/entities/ConsistencyGroupsDEPRECATED/action.json +147 -0
  46. package/entities/ConsistencyGroupsDEPRECATED/schema.json +58 -0
  47. package/entities/DefaultVolumeTypesDefaultTypes/action.json +86 -0
  48. package/entities/DefaultVolumeTypesDefaultTypes/schema.json +33 -0
  49. package/entities/GenericVolumeGroupsGroups/action.json +147 -0
  50. package/entities/GenericVolumeGroupsGroups/schema.json +69 -0
  51. package/entities/GroupSnapshotsGroupSnapshots/action.json +127 -0
  52. package/entities/GroupSnapshotsGroupSnapshots/schema.json +79 -0
  53. package/entities/GroupTypeSpecsGroupTypesGroupSpecs/action.json +106 -0
  54. package/entities/GroupTypeSpecsGroupTypesGroupSpecs/schema.json +56 -0
  55. package/entities/GroupTypesGroupTypes/action.json +127 -0
  56. package/entities/GroupTypesGroupTypes/schema.json +46 -0
  57. package/entities/HostsExtensionOsHosts/action.json +46 -0
  58. package/entities/HostsExtensionOsHosts/schema.json +42 -0
  59. package/entities/LimitsLimits/action.json +25 -0
  60. package/entities/LimitsLimits/schema.json +30 -0
  61. package/entities/MessagesMessages/action.json +66 -0
  62. package/entities/MessagesMessages/schema.json +43 -0
  63. package/entities/QualityOfServiceQoSSpecificationsQosSpecs/action.json +210 -0
  64. package/entities/QualityOfServiceQoSSpecificationsQosSpecs/schema.json +61 -0
  65. package/entities/QuotaClassSetExtensionOsQuotaClassSets/action.json +45 -0
  66. package/entities/QuotaClassSetExtensionOsQuotaClassSets/schema.json +42 -0
  67. package/entities/QuotaSetsExtensionOsQuotaSets/action.json +86 -0
  68. package/entities/QuotaSetsExtensionOsQuotaSets/schema.json +44 -0
  69. package/entities/ResourceFiltersResourceFilters/action.json +25 -0
  70. package/entities/ResourceFiltersResourceFilters/schema.json +30 -0
  71. package/entities/ServicesOsServices/action.json +185 -0
  72. package/entities/ServicesOsServices/schema.json +38 -0
  73. package/entities/SnapshotActionsSnapshotsAction/action.json +24 -0
  74. package/entities/SnapshotActionsSnapshotsAction/schema.json +41 -0
  75. package/entities/SnapshotManageExtensionManageableSnapshots/action.json +66 -0
  76. package/entities/SnapshotManageExtensionManageableSnapshots/schema.json +32 -0
  77. package/entities/VolumeActionsVolumesAction/action.json +24 -0
  78. package/entities/VolumeActionsVolumesAction/schema.json +41 -0
  79. package/entities/VolumeManageExtensionManageableVolumes/action.json +66 -0
  80. package/entities/VolumeManageExtensionManageableVolumes/schema.json +32 -0
  81. package/entities/VolumeSnapshotsSnapshots/action.json +249 -0
  82. package/entities/VolumeSnapshotsSnapshots/schema.json +85 -0
  83. package/entities/VolumeTransfer/action.json +127 -0
  84. package/entities/VolumeTransfer/schema.json +57 -0
  85. package/entities/VolumeTransfersVolumeTransfers355OrLater/action.json +127 -0
  86. package/entities/VolumeTransfersVolumeTransfers355OrLater/schema.json +79 -0
  87. package/entities/VolumeTypeAccessTypesActionTypesOsVolumeTypeAccess/action.json +45 -0
  88. package/entities/VolumeTypeAccessTypesActionTypesOsVolumeTypeAccess/schema.json +42 -0
  89. package/entities/VolumeTypesTypes/action.json +331 -0
  90. package/entities/VolumeTypesTypes/schema.json +78 -0
  91. package/entities/VolumesVolumes/action.json +270 -0
  92. package/entities/VolumesVolumes/schema.json +108 -0
  93. package/entities/WorkersWorkers/action.json +24 -0
  94. package/entities/WorkersWorkers/schema.json +30 -0
  95. package/error.json +190 -0
  96. package/package.json +87 -0
  97. package/pronghorn.json +10093 -0
  98. package/propertiesDecorators.json +14 -0
  99. package/propertiesSchema.json +1284 -0
  100. package/refs?service=git-upload-pack +0 -0
  101. package/report/adapterInfo.json +10 -0
  102. package/report/cinder-openapi.json +8589 -0
  103. package/report/creationReport.json +1495 -0
  104. package/sampleProperties.json +198 -0
  105. package/swagger/openstack_API_docs/BlockStorageAPIV3-cinder-documentation.html +32674 -0
  106. package/swagger/openstack_api_cinder.js +602 -0
  107. package/test/integration/adapterTestBasicGet.js +85 -0
  108. package/test/integration/adapterTestConnectivity.js +93 -0
  109. package/test/integration/adapterTestIntegration.js +4799 -0
  110. package/test/unit/adapterBaseTestUnit.js +952 -0
  111. package/test/unit/adapterTestUnit.js +7633 -0
  112. package/utils/adapterInfo.js +206 -0
  113. package/utils/addAuth.js +94 -0
  114. package/utils/artifactize.js +146 -0
  115. package/utils/basicGet.js +50 -0
  116. package/utils/checkMigrate.js +63 -0
  117. package/utils/entitiesToDB.js +179 -0
  118. package/utils/findPath.js +74 -0
  119. package/utils/methodDocumentor.js +225 -0
  120. package/utils/modify.js +154 -0
  121. package/utils/packModificationScript.js +35 -0
  122. package/utils/patches2bundledDeps.js +90 -0
  123. package/utils/pre-commit.sh +32 -0
  124. package/utils/removeHooks.js +20 -0
  125. package/utils/setup.js +33 -0
  126. package/utils/tbScript.js +184 -0
  127. package/utils/tbUtils.js +469 -0
  128. package/utils/testRunner.js +298 -0
  129. package/utils/troubleshootingAdapter.js +190 -0
  130. package/workflows/README.md +3 -0
@@ -0,0 +1,602 @@
1
+ /* eslint-disable */
2
+ const fs = require('fs');
3
+ const util = require('util');
4
+ const parse5 = require('parse5');
5
+ const htmlparser2 = require("htmlparser2");
6
+ const domutils = require("domutils");
7
+ const { Parser } = require("htmlparser2");
8
+ const { DomHandler } = require("domhandler");
9
+ const toJsonSchema = require('to-json-schema');
10
+ const { stringify } = require('yaml')
11
+
12
+ const inspect = obj => util.inspect(obj, { depth: Infinity });
13
+
14
+ const htmlFile = fs.readFileSync('/home/bota/IAP/apps/node_practice/openstack_API_docs/BlockStorageAPIV3-cinder-documentation.html', { encoding: 'utf-8' })
15
+ const outputFileName = 'cinder-openapi.json'
16
+
17
+ const changeToCamelCase = (s) => {
18
+ let operationId = "";
19
+ s.split(" ").forEach((word, index) => {
20
+ let firstLetter;
21
+ if (index === 0) {
22
+ firstLetter = word[0].toLowerCase()
23
+ } else {
24
+ firstLetter = word[0].toUpperCase()
25
+ }
26
+ operationId += firstLetter + word.slice(1);
27
+ })
28
+ return operationId;
29
+ }
30
+
31
+ const getTag = (node) => {
32
+ const siblings = domutils.getSiblings(node);
33
+ const h2 = domutils.filter(elem => elem.name === 'h2', siblings);
34
+ let tag = '';
35
+ if (h2.length !== 1) {
36
+ console.error('Can not obtain tag')
37
+ return tag;
38
+ }
39
+ const tagNode = h2[0];
40
+ const tagNodetext = domutils.getChildren(tagNode).filter(elem => elem.type === 'text', tagNode);
41
+ tag = domutils.innerText(tagNodetext).trim();
42
+ return tag;
43
+ }
44
+
45
+ const getRestMethod = (node) => {
46
+ const n = domutils.findOne((e => e.name === 'span' && e.attribs.class.split(' ').find(item => item === 'label')), [node]);
47
+ const restMethod = domutils.innerText(n).trim().toLocaleLowerCase();
48
+ return restMethod;
49
+ }
50
+
51
+ const getPath = (node) => {
52
+ const n = domutils.findOne((e => e.name === 'div' && e.attribs.class === 'endpoint-container'), [node]);
53
+ const childs = domutils.getElementsByTagName('div', domutils.getChildren(n), false);
54
+ const pathNode = childs[0];
55
+ const path = domutils.innerText(pathNode).trim();
56
+ return path;
57
+ }
58
+
59
+ const getDescription = (node) => {
60
+ const n = domutils.findOne((e => e.name === 'div' && e.attribs.class === 'endpoint-container'), [node]);
61
+ const childs = domutils.getElementsByTagName('div', domutils.getChildren(n), false);
62
+ const descriptionNode = childs[1];
63
+ const path = domutils.innerText(descriptionNode).trim();
64
+ return path;
65
+ }
66
+
67
+ const getDetailsLink = (node) => {
68
+ const n = domutils.findOne((e => e.name === 'div' && e.attribs.class === 'operation'), [node]);
69
+ const childs = domutils.getElementsByTagName('a', domutils.getChildren(n), true);
70
+ if (childs.length !== 1) {
71
+ return 'No link found';
72
+ }
73
+ const detailsLinkNode = childs[0];
74
+ const detailsLink = detailsLinkNode.attribs.href;
75
+ return detailsLink;
76
+ }
77
+
78
+ const getRequestSchema = (section) => {
79
+ let requestSchema = {}
80
+ if(!section) return requestSchema;
81
+ let exampleNode = domutils.findOne((elem) => elem.name === 'div' && (elem.attribs.class && elem.attribs.class.startsWith('highlight-javascript')), [section], true);
82
+ if (exampleNode) {
83
+ // console.log('exampleNode 1', exampleNode, domutils.textContent(exampleNode).trim());
84
+ // console.log('exampleNode 1 CONTENT', domutils.textContent(exampleNode).trim());
85
+ const s = domutils.textContent(exampleNode).trim();
86
+ try {
87
+ let o = JSON.parse(s);
88
+ requestSchema = toJsonSchema(o);
89
+ } catch (err) { }
90
+
91
+ // const requestSchema = stringify(schema);
92
+ // console.log('YAML schema', requestSchema)
93
+ }
94
+ console.log('example', JSON.stringify(requestSchema));
95
+ return requestSchema;
96
+ }
97
+
98
+ const getRequest = (node) => {
99
+ const requestParameters = [];
100
+ let requestSchema = {}
101
+ const sections = domutils.getElementsByTagName('section', domutils.getChildren(node), false);
102
+
103
+ let requestSection = sections.find(s => {
104
+ let textNodes = domutils.getElementsByTagName('h4', domutils.getChildren(s), false);
105
+ return domutils.textContent(textNodes).includes('Request');
106
+ });
107
+
108
+ let requestExampleSection = sections.find(s => {
109
+ let textNodes = domutils.getElementsByTagName('h4', domutils.getChildren(s), false);
110
+ return domutils.textContent(textNodes).includes('Request Example');
111
+ });
112
+
113
+ if (!requestSection && !requestExampleSection) return {requestParameters, requestSchema};
114
+
115
+ requestSchema = getRequestSchema(requestExampleSection);
116
+
117
+ const subSections = domutils.getElementsByTagName('section', domutils.getChildren(requestSection), false);
118
+ let requestParamtersSection = subSections.find(s => {
119
+ let textNodes = domutils.getElementsByTagName('h5', domutils.getChildren(s), false);
120
+ return domutils.textContent(textNodes).includes('Parameters');
121
+ });
122
+
123
+ // TODO Add support for multiple requests/responses
124
+ const table = domutils.getElementsByTagName('tbody', requestParamtersSection || requestSection);
125
+ const allRows = domutils.getElementsByTagName('tr', table);
126
+
127
+ allRows.forEach((row) => {
128
+ let parameter = {};
129
+ let columns = domutils.getElementsByTagName('p', row);
130
+ columns.forEach((c, index) => {
131
+ let t = domutils.innerText(c).replace(/[\r\n]\s+/g, ' ').trim();
132
+ switch (index) {
133
+ case 0:
134
+ parameter.name = t;
135
+ break;
136
+ case 1:
137
+ parameter.in = t;
138
+ break;
139
+ case 2:
140
+ parameter.type = t;
141
+ break;
142
+ case 3:
143
+ parameter.description = t;
144
+ break;
145
+ }
146
+ });
147
+ requestParameters.push(parameter);
148
+ });
149
+
150
+ return { requestParameters, requestSchema };
151
+ }
152
+
153
+ const getResponse = (node) => {
154
+ let response = [];
155
+ const sections = domutils.getElementsByTagName('section', domutils.getChildren(node), false);
156
+
157
+ let responseSection = sections.find(s => {
158
+ let textNodes = domutils.getElementsByTagName('h4', domutils.getChildren(s), false);
159
+ return domutils.textContent(textNodes).includes('Response');
160
+ });
161
+ if (!responseSection) return response;
162
+
163
+ const subSections = domutils.getElementsByTagName('section', domutils.getChildren(responseSection), false);
164
+ let responseParamtersSection = subSections.find(s => {
165
+ let textNodes = domutils.getElementsByTagName('h4', domutils.getChildren(s), false);
166
+ return domutils.textContent(textNodes).includes('Parameters');
167
+ });
168
+ if (!responseParamtersSection) return response
169
+ // TODO Add support for multiple requests/responses
170
+ const table = domutils.getElementsByTagName('tbody', responseParamtersSection);
171
+ const allRows = domutils.getElementsByTagName('tr', table);
172
+
173
+ allRows.forEach((row) => {
174
+ let parameter = {};
175
+ let columns = domutils.getElementsByTagName('p', row);
176
+ columns.forEach((c, index) => {
177
+ let t = domutils.innerText(c).replace(/[\r\n]\s+/g, ' ').trim();
178
+ switch (index) {
179
+ case 0:
180
+ parameter.name = t;
181
+ break;
182
+ case 1:
183
+ parameter.in = t;
184
+ break;
185
+ case 2:
186
+ parameter.type = t;
187
+ break;
188
+ case 3:
189
+ parameter.description = t;
190
+ break;
191
+ }
192
+ });
193
+ response.push(parameter);
194
+ });
195
+ return response;
196
+ }
197
+
198
+ const getStatusCodes = (node) => {
199
+ let statusCodes = [];
200
+ const sections = domutils.getElementsByTagName('section', domutils.getChildren(node), true);
201
+
202
+ let responseSection = sections.find(s => {
203
+ let textNodes = domutils.getElementsByTagName('h4', domutils.getChildren(s), false);
204
+ return domutils.textContent(textNodes).includes('Response');
205
+ });
206
+
207
+ let statusCodesSection = sections.find(s => {
208
+ let textNodes = domutils.getElementsByTagName('h5', domutils.getChildren(s), false);
209
+ return domutils.textContent(textNodes).includes('Status Codes');
210
+ });
211
+
212
+ let statusCodesSuccessSection = sections.find(s => {
213
+ let textNodes = domutils.getElementsByTagName('h5', domutils.getChildren(s), false);
214
+ return domutils.textContent(textNodes).includes('Success');
215
+ });
216
+
217
+ let statusCodesErrorSection = sections.find(s => {
218
+ let textNodes = domutils.getElementsByTagName('h5', domutils.getChildren(s), false);
219
+ return domutils.textContent(textNodes).includes('Error');
220
+ });
221
+
222
+ if (statusCodesSuccessSection) {
223
+ const rows = domutils.getElementsByTagName('td', domutils.getChildren(statusCodesSuccessSection));
224
+ rows.forEach((r, index) => {
225
+ if (index % 2 === 0) {
226
+ statusCodes.push({ code: domutils.innerText(r).trim(), reason: domutils.innerText(rows[index + 1]).trim() })
227
+ }
228
+ })
229
+ }
230
+ if (statusCodesErrorSection) {
231
+ const rows = domutils.getElementsByTagName('td', domutils.getChildren(statusCodesErrorSection));
232
+ rows.forEach((r, index) => {
233
+ if (index % 2 === 0) {
234
+ statusCodes.push({ code: domutils.innerText(r).trim(), reason: domutils.innerText(rows[index + 1]).trim() })
235
+ }
236
+ })
237
+ }
238
+
239
+ if (statusCodesSection && !statusCodesSuccessSection && !statusCodesErrorSection) {
240
+ const rows = domutils.getElementsByTagName('td', domutils.getChildren(statusCodesSection));
241
+ rows.forEach((r, index) => {
242
+ if (index % 2 === 0) {
243
+ statusCodes.push({ code: domutils.innerText(r).trim(), reason: domutils.innerText(rows[index + 1]).trim() })
244
+ }
245
+ })
246
+ }
247
+
248
+ if (statusCodes.length === 0) {
249
+ statusCodes.push({ code: "200 - OK", reason: "Request was successful." })
250
+ }
251
+ return statusCodes;
252
+ }
253
+
254
+ const extractData = (detailControlNodes, apiDetailControlNodes) => {
255
+ const N = detailControlNodes.length;
256
+ let data = [];
257
+ console.log("Operations found:");
258
+ for (let i = 0; i < N; i += 1) {
259
+ console.log('\n======= OPERATION ========\n');
260
+ const node = detailControlNodes[i];
261
+ const detailsNode = apiDetailControlNodes[i];
262
+
263
+ const tag = getTag(node);
264
+ const restMethod = getRestMethod(node);
265
+ const path = getPath(node);
266
+ const description = getDescription(node);
267
+ const detailsLink = getDetailsLink(node);
268
+ console.log(`> Operation:\n| ${restMethod} | ${path} | ${description} | ${detailsLink} |`);
269
+ const { requestParameters, requestSchema } = getRequest(detailsNode);
270
+ console.log(`> Request parameters:\n|${inspect(requestParameters)}|${inspect(requestSchema)}`);
271
+ const response = getResponse(detailsNode);
272
+ console.log(`> Response parameters:\n|${inspect(response)}|`);
273
+ const statusCodes = getStatusCodes(detailsNode);
274
+ console.log(`> Response status codes:\n|${inspect(statusCodes)}|`);
275
+ data.push({ restMethod, path, description, detailsLink, response, requestParameters, requestSchema, statusCodes, tag });
276
+ }
277
+ return data;
278
+ }
279
+
280
+ const saveToFile = (obj) => {
281
+ fs.writeFileSync(outputFileName, JSON.stringify(obj));
282
+ console.log(`File '${outputFileName}' saved.`)
283
+ }
284
+
285
+ const getBaseOpenApiObj = () => {
286
+ const openApiObj = {
287
+ openapi: "3.0.0",
288
+ info: {
289
+ version: "1.0",
290
+ title: "Openstack Cinder API"
291
+ },
292
+ servers: [
293
+ {
294
+ url: 'http://{host}:{port}',
295
+ description: 'Block Storage service (cinder) administrative endpoint',
296
+ variables: {
297
+ host: {
298
+ default: "localhost"
299
+ },
300
+ port: {
301
+ default: "8776"
302
+ }
303
+ }
304
+ }
305
+ ],
306
+ paths: {
307
+ },
308
+ components: { schemas: {}, responses: {}, parameters: {}, examples: {}, requestBodies: {}, headers: {}, securitySchemes: {}, links: {}, callbacks: {} },
309
+ security: [],
310
+ tags: [],
311
+ externalDocs: {
312
+ description: 'Openstack Cinder Block Storage API Operations',
313
+ url: 'https://docs.openstack.org/api-ref/block-storage/v3/index.html?expanded=#'
314
+ }
315
+ }
316
+
317
+ openApiObj.components.securitySchemes = {
318
+ token: {
319
+ type: "apiKey",
320
+ description: 'Token authentication',
321
+ name: "X-Auth-Token",
322
+ in: "header"
323
+ }
324
+ }
325
+
326
+ openApiObj.security = [{ "token": [] }];
327
+
328
+ return openApiObj;
329
+ }
330
+
331
+ const buildQueryParameters = (operation) => {
332
+ let params = []
333
+ let queryParams = operation.filter((item) => item.in === 'query')
334
+ queryParams.forEach((p) => {
335
+ isOptional = false
336
+ if (p.name.indexOf('Optional') !== -1) {
337
+ isOptional = true;
338
+ p.name = p.name.split(' ')[0].trim();
339
+ }
340
+ if (p.type.includes('key-only')) {
341
+ params.push({
342
+ "name": p.name,
343
+ "in": p.in,
344
+ "required": !isOptional,
345
+ "schema": {
346
+ "type": 'boolean',
347
+ "description": p.description
348
+ },
349
+ "allowEmptyValue": true
350
+ })
351
+ } else {
352
+ if (p.type.includes('bool')) p.type = 'boolean'
353
+ params.push({
354
+ "name": p.name,
355
+ "in": p.in,
356
+ "required": !isOptional,
357
+ "schema": {
358
+ "type": p.type,
359
+ "description": p.description
360
+ }
361
+ })
362
+ }
363
+ });
364
+ return params;
365
+ }
366
+
367
+ const buildHeaderParameters = (operation) => {
368
+ let params = []
369
+ let headerParams = operation.filter((item) => item.in === 'header')
370
+
371
+ headerParams.forEach((p) => {
372
+ isOptional = false
373
+ if (p.name.indexOf('Optional') !== -1) {
374
+ isOptional = true;
375
+ p.name = p.name.split(' ')[0].trim();
376
+ }
377
+ params.push({
378
+ "name": p.name,
379
+ "in": p.in,
380
+ "required": !isOptional,
381
+ "schema": {
382
+ "type": p.type,
383
+ "description": p.description
384
+ }
385
+ })
386
+ });
387
+ return params;
388
+ }
389
+
390
+ const buildPathParameters = (operation) => {
391
+ let params = []
392
+ let pathParams = operation.filter((item) => item.in === 'path')
393
+ pathParams.forEach((p) => {
394
+ isOptional = false
395
+ if (p.name.indexOf('Optional') !== -1) {
396
+ isOptional = true;
397
+ p.name = p.name.split(' ')[0].trim();
398
+ }
399
+ params.push({
400
+ "name": p.name,
401
+ "in": p.in,
402
+ "required": !isOptional,
403
+ "schema": {
404
+ "type": p.type,
405
+ "description": p.description
406
+ }
407
+ })
408
+ });
409
+ return params;
410
+ }
411
+
412
+ const buildRequestBody = (request, requestSchema) => {
413
+ // let bodyParams = request.filter((item) => item.in === 'body')
414
+ let requestBody = {
415
+ "content": {
416
+ "application/json": {
417
+ "schema": requestSchema
418
+ }
419
+ }
420
+ };
421
+
422
+ isBodyPresent = Object.keys(requestSchema).length > 0;
423
+ // required = [];
424
+ // bodyParams.forEach((bodyParam) => {
425
+ // let propertyName = bodyParam.name.split(' ')[0];
426
+ // if (!bodyParam.name.includes('Optional')) {
427
+ // required.push(propertyName);
428
+ // }
429
+ // requestBody.content["application/json"].schema.properties[propertyName] = {};
430
+ // if (bodyParam.type === 'list') {
431
+ // bodyParam.type = 'array';
432
+ // }
433
+ // requestBody.content["application/json"].schema.properties[propertyName].type = bodyParam.type
434
+ // if (bodyParam.type === 'array') {
435
+ // let type = '';
436
+ // if (bodyParam.description.includes('object')) {
437
+ // type = 'object';
438
+ // } else if (bodyParam.description.includes('string')) {
439
+ // type = 'string';
440
+ // } else {
441
+ // type = 'string';
442
+ // }
443
+ // requestBody.content["application/json"].schema.properties[propertyName].items = {
444
+ // type
445
+ // }
446
+ // }
447
+ // requestBody.content["application/json"].schema.properties[propertyName].description = bodyParam.description
448
+ // });
449
+
450
+ // if (required.length > 0) {
451
+ // requestBody.content["application/json"].schema.required = required;
452
+ // }
453
+
454
+ return { isBodyPresent, requestBody };
455
+ }
456
+
457
+ const buildResponseBody = (operation) => {
458
+ const responseBody = {
459
+ "headers": {},
460
+ "content": {
461
+ "application/json": {
462
+ "schema": {
463
+ "type": "object",
464
+ "properties": {}
465
+ }
466
+ }
467
+ }
468
+ };
469
+
470
+ let headerParams = operation.filter((item) => item.in === 'header');
471
+ headerParams.forEach((headerParam) => {
472
+ responseBody.headers[headerParam.name] = {
473
+ "description": headerParam.description,
474
+ "schema": {
475
+ "type": headerParam.type
476
+ }
477
+ };
478
+ });
479
+
480
+ let bodyParams = operation.filter((item) => item.in === 'body')
481
+ isBodyPresent = bodyParams.length > 0;
482
+ const required = new Set();
483
+ bodyParams.forEach((bodyParam) => {
484
+ let propertyName = bodyParam.name.split(' ')[0];
485
+ if (!bodyParam.name.includes('Optional')) {
486
+ required.add(propertyName);
487
+ }
488
+ responseBody.content["application/json"].schema.properties[propertyName] = {};
489
+ if (bodyParam.type === 'list') {
490
+ bodyParam.type = 'array';
491
+ }
492
+ responseBody.content["application/json"].schema.properties[propertyName].type = bodyParam.type
493
+ if (bodyParam.type === 'array') {
494
+ let type = '';
495
+ if (bodyParam.description.includes('object')) {
496
+ type = 'object';
497
+ } else if (bodyParam.description.includes('string')) {
498
+ type = 'string';
499
+ } else {
500
+ type = 'string';
501
+ }
502
+ responseBody.content["application/json"].schema.properties[propertyName].items = {
503
+ type
504
+ }
505
+ }
506
+ responseBody.content["application/json"].schema.properties[propertyName].description = bodyParam.description
507
+ });
508
+
509
+ if (required.size > 0) {
510
+ responseBody.content["application/json"].schema.required = [...required];
511
+ }
512
+
513
+ return { isBodyPresent, responseBody };
514
+ }
515
+
516
+ const buildResponses = (statusCodes, response) => {
517
+ const responses = {}
518
+ statusCodes.forEach((item) => {
519
+ let code = item.code.split(' ')[0];
520
+ responses[code] = { "description": item.reason }
521
+ });
522
+ // const { isBodyPresent, responseBody } = buildResponseBody(response);
523
+ // const successfullResponse = Object.keys(responses).find(k => k.startsWith('2'));
524
+ // console.log('successfullResponse', successfullResponse);
525
+ // if (isBodyPresent) {
526
+ // console.log('responseBody', responseBody);
527
+ // Object.assign(responses[successfullResponse], responseBody);
528
+ // }
529
+ return responses;
530
+ }
531
+
532
+ const createOpenApiFile = (data) => {
533
+ const openApiObj = getBaseOpenApiObj();
534
+
535
+ const allEndpoints = new Set()
536
+ data.forEach((item) => allEndpoints.add(item.path))
537
+ console.log('\nFound:', allEndpoints.size, 'endpoints\n');
538
+
539
+ allEndpoints.forEach(endpoint => {
540
+ console.log('Processing endpoint', endpoint);
541
+
542
+ allEndpointOperations = data.filter(item => item.path === endpoint)
543
+ console.log(`Found ${allEndpointOperations.length} operations\n`);
544
+
545
+ openApiObj.paths[endpoint] = {};
546
+
547
+ let pathOpenAPI = openApiObj.paths[endpoint];
548
+
549
+ allEndpointOperations.forEach(op => {
550
+ if (pathOpenAPI[op.restMethod]) {
551
+ console.error('More then 1 operation for same (URIpath, restMethod) set, skipping...');
552
+ return;
553
+ }
554
+ pathOpenAPI[op.restMethod] = { operationId: changeToCamelCase(op.description) };
555
+ pathOpenAPI[op.restMethod].summary = op.description;
556
+ pathOpenAPI[op.restMethod].externalDocs = { url: op.detailsLink }
557
+
558
+ let queryParams = buildQueryParameters(op.requestParameters);
559
+ let headerParams = buildHeaderParameters(op.requestParameters);
560
+ let pathParams = buildPathParameters(op.requestParameters);
561
+ if (queryParams.length + headerParams.length + pathParams.length > 0) {
562
+ pathOpenAPI[op.restMethod].parameters = queryParams.concat(headerParams).concat(pathParams);
563
+ }
564
+
565
+ let { isBodyPresent, requestBody } = buildRequestBody(op.requestParameters, op.requestSchema);
566
+ if (isBodyPresent) {
567
+ pathOpenAPI[op.restMethod].requestBody = requestBody;
568
+ }
569
+
570
+ pathOpenAPI[op.restMethod].responses = buildResponses(op.statusCodes, op.response);
571
+
572
+ if (op.tag) {
573
+ if (!pathOpenAPI[op.restMethod].tags) {
574
+ pathOpenAPI[op.restMethod].tags = [];
575
+ }
576
+ pathOpenAPI[op.restMethod].tags.push(op.tag);
577
+ }
578
+ })
579
+ })
580
+
581
+ saveToFile(openApiObj);
582
+ }
583
+
584
+ const handler = new DomHandler((error, dom) => {
585
+ if (error) {
586
+ } else {
587
+ let detailControlNodes = domutils.findAll((element) => element.name === "section" && element.attribs.class === 'detail-control', dom);
588
+ let apiDetailControlNodes = domutils.findAll((element) => element.name === "section" && element.attribs.class === 'api-detail collapse', dom);
589
+
590
+ console.log('Nodes count:', detailControlNodes.length, apiDetailControlNodes.length);
591
+ if (detailControlNodes.length !== apiDetailControlNodes.length) {
592
+ console.error('Count mismatch');
593
+ throw new Error();
594
+ }
595
+ const data = extractData(detailControlNodes, apiDetailControlNodes);
596
+ createOpenApiFile(data);
597
+ }
598
+ });
599
+
600
+ const parser = new Parser(handler);
601
+ parser.write(htmlFile);
602
+ parser.end();
@@ -0,0 +1,85 @@
1
+ /* @copyright Itential, LLC 2020 */
2
+
3
+ /* global describe context before after */
4
+ /* eslint global-require: warn */
5
+ /* eslint no-unused-vars: warn */
6
+ /* eslint import/no-extraneous-dependencies: warn */
7
+ /* eslint import/no-dynamic-require: warn */
8
+ /* eslint import/no-unresolved: warn */
9
+
10
+ const mocha = require('mocha');
11
+ const path = require('path');
12
+ const assert = require('assert');
13
+ const itParam = require('mocha-param');
14
+
15
+ const utils = require('../../utils/tbUtils');
16
+ const basicGet = require('../../utils/basicGet');
17
+ const { name } = require('../../package.json');
18
+ const { methods } = require('../../pronghorn.json');
19
+
20
+ const getPronghornProps = (iapDir) => {
21
+ const { Discovery } = require('@itential/itential-utils');
22
+ console.log('Retrieving properties.json file...');
23
+ const rawProps = require(path.join(iapDir, 'properties.json'));
24
+ console.log('Decrypting properties...');
25
+ const discovery = new Discovery();
26
+ const pronghornProps = utils.decryptProperties(rawProps, path.join(__dirname, '..'), discovery);
27
+ console.log('Found properties.\n');
28
+ return pronghornProps;
29
+ };
30
+
31
+ let a;
32
+
33
+ describe('[integration] Adapter BasicGET Test', () => {
34
+ context('Testing GET calls without query parameters', () => {
35
+ before(async () => {
36
+ const iapDir = path.join(__dirname, '../../../../../');
37
+ if (!utils.areWeUnderIAPinstallationDirectory()) {
38
+ const sampleProperties = require('../../sampleProperties.json');
39
+ const adapter = { properties: sampleProperties };
40
+ a = basicGet.getAdapterInstance(adapter);
41
+ } else {
42
+ const pronghornProps = getPronghornProps(iapDir);
43
+ console.log('Connecting to Database...');
44
+ const database = await basicGet.connect(pronghornProps);
45
+ console.log('Connection established.');
46
+ const adapter = await database.collection(utils.SERVICE_CONFIGS_COLLECTION).findOne(
47
+ { model: name }
48
+ );
49
+ a = basicGet.getAdapterInstance(adapter);
50
+ }
51
+ });
52
+
53
+ after((done) => {
54
+ done();
55
+ });
56
+
57
+ const basicGets = methods.filter((method) => (method.route.verb === 'GET' && method.input.length === 0));
58
+ if (basicGets.length === 0) {
59
+ console.log('No non-parameter GET calls found.');
60
+ process.exit(0);
61
+ }
62
+ const functionNames = basicGets.map((g) => g.name);
63
+ const request = function request(f, ad) {
64
+ return new Promise((resolve, reject) => {
65
+ const getRespCode = (resp) => {
66
+ if (resp) {
67
+ if (resp.metrics.code !== 200) {
68
+ console.log('\x1b[31m', `Testing ${f} \nResponseCode: ${resp.metrics.code}`);
69
+ }
70
+ resolve(resp.metrics.code);
71
+ } else {
72
+ console.log('\x1b[31m', `call ${f} results in failure`);
73
+ reject(new Error(`${f} failed`));
74
+ }
75
+ };
76
+ ad[f](getRespCode, console.log);
77
+ });
78
+ };
79
+
80
+ itParam('GET call should return 200', functionNames, (fname) => {
81
+ console.log(`\t ${fname}`);
82
+ return request(fname, a).then((result) => assert.equal(result, 200));
83
+ });
84
+ });
85
+ });