@aifabrix/builder 2.32.2 → 2.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.cursor/rules/project-rules.mdc +8 -0
  2. package/README.md +36 -8
  3. package/bin/aifabrix.js +6 -8
  4. package/integration/hubspot/README.md +8 -7
  5. package/integration/hubspot/companies.json +2048 -0
  6. package/integration/hubspot/create-hubspot.js +665 -0
  7. package/integration/hubspot/{hubspot-deploy-company.json → hubspot-datasource-company.json} +1 -1
  8. package/integration/hubspot/{hubspot-deploy-contact.json → hubspot-datasource-contact.json} +1 -1
  9. package/integration/hubspot/{hubspot-deploy-deal.json → hubspot-datasource-deal.json} +1 -1
  10. package/integration/hubspot/hubspot-deploy.json +832 -81
  11. package/integration/hubspot/hubspot-system.json +99 -0
  12. package/integration/hubspot/test-artifacts/wizard-hubspot-credential-real.yaml +20 -0
  13. package/integration/hubspot/test-artifacts/wizard-hubspot-env-vars.yaml +9 -0
  14. package/integration/hubspot/test-artifacts/wizard-invalid-add-datasource.yaml +5 -0
  15. package/integration/hubspot/test-artifacts/wizard-invalid-app-name.yaml +5 -0
  16. package/integration/hubspot/test-artifacts/wizard-invalid-credential-create.yaml +7 -0
  17. package/integration/hubspot/test-artifacts/wizard-invalid-credential-select.yaml +7 -0
  18. package/integration/hubspot/test-artifacts/wizard-invalid-known-platform.yaml +4 -0
  19. package/integration/hubspot/test-artifacts/wizard-invalid-missing-app.yaml +4 -0
  20. package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
  21. package/integration/hubspot/test-artifacts/wizard-invalid-mode.yaml +5 -0
  22. package/integration/hubspot/test-artifacts/wizard-invalid-openapi-file.yaml +5 -0
  23. package/integration/hubspot/test-artifacts/wizard-invalid-openapi-url.yaml +4 -0
  24. package/integration/hubspot/test-artifacts/wizard-invalid-source.yaml +4 -0
  25. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-array-test.yaml +5 -0
  26. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
  27. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
  28. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-test.yaml +5 -0
  29. package/integration/hubspot/test-artifacts/wizard-valid-for-rbac-test.yaml +5 -0
  30. package/integration/hubspot/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +5 -0
  31. package/integration/hubspot/test-dataplane-down-helpers.js +246 -0
  32. package/integration/hubspot/test-dataplane-down-tests.js +419 -0
  33. package/integration/hubspot/test-dataplane-down.js +157 -0
  34. package/integration/hubspot/test.js +1517 -0
  35. package/integration/hubspot/variables.yaml +4 -4
  36. package/integration/hubspot/wizard-hubspot-e2e.yaml +16 -0
  37. package/integration/hubspot/wizard-hubspot-platform.yaml +8 -0
  38. package/lib/api/applications.api.js +1 -0
  39. package/lib/api/index.js +10 -5
  40. package/lib/api/types/wizard.types.js +176 -38
  41. package/lib/api/wizard.api.js +207 -38
  42. package/lib/app/deploy.js +116 -54
  43. package/lib/app/display.js +6 -5
  44. package/lib/app/dockerfile.js +2 -1
  45. package/lib/app/list.js +78 -37
  46. package/lib/app/prompts.js +9 -5
  47. package/lib/app/readme.js +41 -112
  48. package/lib/app/register.js +44 -9
  49. package/lib/app/rotate-secret.js +50 -32
  50. package/lib/cli.js +243 -65
  51. package/lib/commands/app.js +4 -9
  52. package/lib/commands/auth-config.js +125 -0
  53. package/lib/commands/auth-status.js +261 -0
  54. package/lib/commands/datasource.js +3 -6
  55. package/lib/commands/login-credentials.js +4 -4
  56. package/lib/commands/login-device.js +43 -29
  57. package/lib/commands/login.js +22 -13
  58. package/lib/commands/wizard-config-normalizer.js +92 -0
  59. package/lib/commands/wizard-core.js +515 -0
  60. package/lib/commands/wizard-dataplane.js +122 -0
  61. package/lib/commands/wizard-headless.js +115 -0
  62. package/lib/commands/wizard.js +129 -357
  63. package/lib/core/config.js +46 -0
  64. package/lib/core/secrets.js +3 -22
  65. package/lib/core/templates-env.js +1 -1
  66. package/lib/datasource/deploy.js +34 -23
  67. package/lib/datasource/list.js +8 -6
  68. package/lib/deployment/deployer.js +25 -0
  69. package/lib/deployment/environment.js +10 -13
  70. package/lib/external-system/delete.js +151 -0
  71. package/lib/external-system/deploy.js +54 -378
  72. package/lib/external-system/download-helpers.js +45 -65
  73. package/lib/external-system/download.js +34 -13
  74. package/lib/external-system/generator.js +11 -7
  75. package/lib/external-system/test-auth.js +5 -3
  76. package/lib/generator/builders.js +3 -1
  77. package/lib/generator/external-controller-manifest.js +157 -0
  78. package/lib/generator/external-schema-utils.js +236 -0
  79. package/lib/generator/external.js +55 -3
  80. package/lib/generator/index.js +22 -10
  81. package/lib/generator/wizard-prompts.js +33 -10
  82. package/lib/generator/wizard.js +69 -86
  83. package/lib/infrastructure/compose.js +100 -0
  84. package/lib/infrastructure/helpers.js +139 -0
  85. package/lib/infrastructure/index.js +52 -311
  86. package/lib/infrastructure/services.js +168 -0
  87. package/lib/schema/application-schema.json +24 -5
  88. package/lib/schema/external-datasource.schema.json +303 -17
  89. package/lib/schema/external-system.schema.json +1 -1
  90. package/lib/schema/wizard-config.schema.json +234 -0
  91. package/lib/utils/api.js +37 -42
  92. package/lib/utils/app-existence.js +42 -0
  93. package/lib/utils/app-register-config.js +7 -2
  94. package/lib/utils/app-register-display.js +2 -1
  95. package/lib/utils/auth-config-validator.js +92 -0
  96. package/lib/utils/cli-utils.js +3 -1
  97. package/lib/utils/command-header.js +43 -0
  98. package/lib/utils/compose-generator.js +113 -70
  99. package/lib/utils/controller-url.js +115 -0
  100. package/lib/utils/dataplane-health.js +115 -0
  101. package/lib/utils/dataplane-resolver.js +29 -0
  102. package/lib/utils/dev-config.js +6 -2
  103. package/lib/utils/env-copy.js +2 -1
  104. package/lib/utils/env-map.js +2 -1
  105. package/lib/utils/env-ports.js +2 -1
  106. package/lib/utils/env-template.js +1 -1
  107. package/lib/utils/error-formatter.js +149 -28
  108. package/lib/utils/external-readme.js +125 -0
  109. package/lib/utils/help-builder.js +190 -0
  110. package/lib/utils/infra-status.js +13 -3
  111. package/lib/utils/paths.js +17 -2
  112. package/lib/utils/port-resolver.js +111 -0
  113. package/lib/utils/secrets-helpers.js +3 -15
  114. package/lib/utils/secrets-utils.js +2 -2
  115. package/lib/utils/token-manager.js +69 -4
  116. package/lib/utils/variable-transformer.js +7 -2
  117. package/lib/validation/external-manifest-validator.js +202 -0
  118. package/lib/validation/validate-display.js +406 -0
  119. package/lib/validation/validate.js +159 -123
  120. package/lib/validation/validator.js +38 -4
  121. package/lib/validation/wizard-config-validator.js +267 -0
  122. package/package.json +4 -2
  123. package/templates/applications/README.md.hbs +19 -17
  124. package/templates/applications/miso-controller/env.template +1 -1
  125. package/templates/applications/miso-controller/rbac.yaml +7 -7
  126. package/templates/external-system/README.md.hbs +99 -0
  127. package/templates/external-system/external-system.json.hbs +1 -1
  128. package/templates/infra/compose.yaml.hbs +35 -0
  129. package/templates/python/docker-compose.hbs +26 -0
  130. package/templates/typescript/docker-compose.hbs +26 -0
@@ -0,0 +1,419 @@
1
+ /**
2
+ * Test Functions for Dataplane Down Tests
3
+ *
4
+ * Individual test functions for dataplane down test suite.
5
+ *
6
+ * @fileoverview Test functions for dataplane down tests
7
+ * @author AI Fabrix Team
8
+ * @version 2.0.0
9
+ */
10
+ 'use strict';
11
+
12
+ const path = require('path');
13
+ const fs = require('fs').promises;
14
+ const {
15
+ logInfo,
16
+ runCommand,
17
+ validateError,
18
+ isTimeoutResult,
19
+ validateDownloadDeleteResult,
20
+ validateDeleteResult,
21
+ validateWizardResult
22
+ } = require('./test-dataplane-down-helpers');
23
+
24
+ const INVALID_DATAPLANE_URL = 'http://localhost:9999';
25
+ const CONTROLLER_URL = process.env.CONTROLLER_URL || 'http://localhost:3110';
26
+ const ENVIRONMENT = process.env.ENVIRONMENT || 'miso';
27
+ const TEST_APP_NAME = 'test-dataplane-down';
28
+
29
+ /**
30
+ * Creates wizard config file
31
+ * @async
32
+ * @function createWizardConfig
33
+ * @param {string} configPath - Path to config file
34
+ * @returns {Promise<void>} Resolves when config file is created
35
+ */
36
+ async function createWizardConfig(configPath) {
37
+ const configContent = `appName: ${TEST_APP_NAME}
38
+ mode: create-system
39
+ source:
40
+ type: known-platform
41
+ platform: hubspot
42
+ deployment:
43
+ controller: ${CONTROLLER_URL}
44
+ environment: ${ENVIRONMENT}
45
+ dataplane: ${INVALID_DATAPLANE_URL}
46
+ `;
47
+ await fs.writeFile(configPath, configContent, 'utf8');
48
+ }
49
+
50
+ /**
51
+ * Test wizard command with invalid dataplane
52
+ * @async
53
+ * @function testWizard
54
+ * @returns {Promise<Object>} Test result
55
+ */
56
+ async function testWizard() {
57
+ logInfo('\n📋 Testing: wizard command');
58
+
59
+ const configPath = path.join(process.cwd(), 'integration', 'test-wizard-config.yaml');
60
+
61
+ try {
62
+ await createWizardConfig(configPath);
63
+
64
+ const args = [
65
+ 'bin/aifabrix.js',
66
+ 'wizard',
67
+ '--config',
68
+ configPath,
69
+ '--controller',
70
+ CONTROLLER_URL,
71
+ '--environment',
72
+ ENVIRONMENT,
73
+ '--dataplane',
74
+ INVALID_DATAPLANE_URL
75
+ ];
76
+
77
+ const result = await runCommand('node', args);
78
+ const output = `${result.stdout}\n${result.stderr}`;
79
+
80
+ // Clean up config file
81
+ try {
82
+ await fs.unlink(configPath);
83
+ } catch {
84
+ // Ignore cleanup errors
85
+ }
86
+
87
+ return validateWizardResult(result, output);
88
+ } catch (error) {
89
+ return {
90
+ name: 'wizard',
91
+ success: false,
92
+ output: error.message,
93
+ error: error.message
94
+ };
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Test download command with invalid dataplane
100
+ * @async
101
+ * @function testDownload
102
+ * @returns {Promise<Object>} Test result
103
+ */
104
+ async function testDownload() {
105
+ logInfo('\n📥 Testing: download command');
106
+
107
+ const args = [
108
+ 'bin/aifabrix.js',
109
+ 'download',
110
+ 'non-existent-system-that-should-fail',
111
+ '--environment',
112
+ ENVIRONMENT,
113
+ '--controller',
114
+ CONTROLLER_URL
115
+ ];
116
+
117
+ const result = await runCommand('node', args);
118
+ const output = `${result.stdout}\n${result.stderr}`;
119
+
120
+ const expectedPatterns = [
121
+ 'failed to connect',
122
+ 'connection refused',
123
+ 'network error',
124
+ 'econnrefused',
125
+ 'fetch failed',
126
+ 'timeout',
127
+ 'unreachable',
128
+ 'failed to download system',
129
+ 'not found',
130
+ 'external system'
131
+ ];
132
+
133
+ const validation = validateDownloadDeleteResult(result, output, expectedPatterns);
134
+
135
+ return {
136
+ name: 'download',
137
+ success: validation.isValid,
138
+ output: validation.output,
139
+ expectedPatterns: validation.expectedPatterns
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Test delete command with invalid dataplane
145
+ * @async
146
+ * @function testDelete
147
+ * @returns {Promise<Object>} Test result
148
+ */
149
+ async function testDelete() {
150
+ logInfo('\n🗑️ Testing: delete command');
151
+
152
+ const args = [
153
+ 'bin/aifabrix.js',
154
+ 'delete',
155
+ 'non-existent-system-that-should-fail',
156
+ '--type',
157
+ 'external',
158
+ '--environment',
159
+ ENVIRONMENT,
160
+ '--controller',
161
+ CONTROLLER_URL,
162
+ '--yes'
163
+ ];
164
+
165
+ const result = await runCommand('node', args);
166
+ const output = `${result.stdout}\n${result.stderr}`;
167
+
168
+ const expectedPatterns = [
169
+ 'failed to connect',
170
+ 'connection refused',
171
+ 'network error',
172
+ 'econnrefused',
173
+ 'fetch failed',
174
+ 'timeout',
175
+ 'unreachable',
176
+ 'failed to delete',
177
+ 'not found',
178
+ 'external system'
179
+ ];
180
+
181
+ const validation = validateDeleteResult(result, output, expectedPatterns);
182
+
183
+ return {
184
+ name: 'delete',
185
+ success: validation.isValid,
186
+ output: validation.output,
187
+ expectedPatterns: validation.expectedPatterns,
188
+ error: validation.error
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Creates test datasource file
194
+ * @async
195
+ * @function createTestDatasource
196
+ * @param {string} datasourcePath - Path to datasource file
197
+ * @returns {Promise<void>} Resolves when datasource file is created
198
+ */
199
+ async function createTestDatasource(datasourcePath) {
200
+ const datasourceContent = JSON.stringify({
201
+ key: 'test-datasource',
202
+ systemKey: 'test-system',
203
+ displayName: 'Test Datasource',
204
+ entityType: 'company',
205
+ resourceType: 'company'
206
+ }, null, 2);
207
+ await fs.writeFile(datasourcePath, datasourceContent, 'utf8');
208
+ }
209
+
210
+ /**
211
+ * Builds datasource deploy command arguments
212
+ * @function buildDatasourceDeployArgs
213
+ * @param {string} datasourcePath - Path to datasource file
214
+ * @returns {string[]} Command arguments
215
+ */
216
+ function buildDatasourceDeployArgs(datasourcePath) {
217
+ return [
218
+ 'bin/aifabrix.js',
219
+ 'datasource',
220
+ 'deploy',
221
+ 'test-app',
222
+ datasourcePath,
223
+ '--environment',
224
+ ENVIRONMENT,
225
+ '--controller',
226
+ CONTROLLER_URL,
227
+ '--dataplane',
228
+ INVALID_DATAPLANE_URL
229
+ ];
230
+ }
231
+
232
+ /**
233
+ * Gets expected error patterns for datasource deploy
234
+ * @function getDatasourceDeployErrorPatterns
235
+ * @returns {string[]} Expected error patterns
236
+ */
237
+ function getDatasourceDeployErrorPatterns() {
238
+ return [
239
+ 'failed to connect',
240
+ 'connection refused',
241
+ 'network error',
242
+ 'econnrefused',
243
+ 'fetch failed',
244
+ 'timeout',
245
+ 'unreachable',
246
+ 'failed to publish',
247
+ 'deployment failed'
248
+ ];
249
+ }
250
+
251
+ /**
252
+ * Test datasource deploy command with invalid dataplane
253
+ * @async
254
+ * @function testDatasourceDeploy
255
+ * @returns {Promise<Object>} Test result
256
+ */
257
+ async function testDatasourceDeploy() {
258
+ logInfo('\n🚀 Testing: datasource deploy command');
259
+
260
+ const datasourcePath = path.join(process.cwd(), 'integration', 'test-datasource.json');
261
+
262
+ try {
263
+ await createTestDatasource(datasourcePath);
264
+ const args = buildDatasourceDeployArgs(datasourcePath);
265
+ const result = await runCommand('node', args);
266
+ const output = `${result.stdout}\n${result.stderr}`;
267
+
268
+ // Clean up datasource file
269
+ try {
270
+ await fs.unlink(datasourcePath);
271
+ } catch {
272
+ // Ignore cleanup errors
273
+ }
274
+
275
+ const expectedPatterns = getDatasourceDeployErrorPatterns();
276
+ const isValid = !result.success && validateError(output, expectedPatterns);
277
+
278
+ return {
279
+ name: 'datasource deploy',
280
+ success: isValid,
281
+ output,
282
+ expectedPatterns
283
+ };
284
+ } catch (error) {
285
+ return {
286
+ name: 'datasource deploy',
287
+ success: false,
288
+ output: error.message,
289
+ error: error.message
290
+ };
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Determines test app name for integration test
296
+ * @async
297
+ * @function determineTestApp
298
+ * @returns {Promise<string>} Test app name
299
+ */
300
+ async function determineTestApp() {
301
+ const hubspotPath = path.join(process.cwd(), 'integration', 'hubspot');
302
+ try {
303
+ await fs.access(hubspotPath);
304
+ return 'hubspot';
305
+ } catch {
306
+ return 'non-existent-app';
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Test test-integration command with invalid dataplane
312
+ * @async
313
+ * @function testIntegration
314
+ * @returns {Promise<Object>} Test result
315
+ */
316
+ async function testIntegration() {
317
+ logInfo('\n🧪 Testing: test-integration command');
318
+
319
+ const testApp = await determineTestApp();
320
+
321
+ const args = [
322
+ 'bin/aifabrix.js',
323
+ 'test-integration',
324
+ testApp,
325
+ '--environment',
326
+ ENVIRONMENT,
327
+ '--controller',
328
+ CONTROLLER_URL
329
+ ];
330
+
331
+ const result = await runCommand('node', args);
332
+ const output = `${result.stdout}\n${result.stderr}`;
333
+
334
+ const expectedPatterns = [
335
+ 'failed to connect',
336
+ 'connection refused',
337
+ 'network error',
338
+ 'econnrefused',
339
+ 'fetch failed',
340
+ 'timeout',
341
+ 'unreachable',
342
+ 'failed to run integration tests',
343
+ 'not found',
344
+ 'dataplane url not found',
345
+ 'application not found'
346
+ ];
347
+
348
+ const isValid = !result.success && (
349
+ validateError(output, expectedPatterns) ||
350
+ output.includes('Failed') ||
351
+ output.includes('Error') ||
352
+ output.includes('not found')
353
+ );
354
+
355
+ return {
356
+ name: 'test-integration',
357
+ success: isValid,
358
+ output,
359
+ expectedPatterns
360
+ };
361
+ }
362
+
363
+ /**
364
+ * Test dataplane discovery with invalid dataplane
365
+ * @async
366
+ * @function testDataplaneDiscovery
367
+ * @returns {Promise<Object>} Test result
368
+ */
369
+ async function testDataplaneDiscovery() {
370
+ logInfo('\n🌐 Testing: dataplane discovery');
371
+
372
+ const args = [
373
+ 'bin/aifabrix.js',
374
+ 'download',
375
+ 'non-existent-system-for-discovery-test',
376
+ '--environment',
377
+ ENVIRONMENT,
378
+ '--controller',
379
+ CONTROLLER_URL
380
+ ];
381
+
382
+ const result = await runCommand('node', args);
383
+ const output = `${result.stdout}\n${result.stderr}`;
384
+
385
+ const expectedPatterns = [
386
+ 'failed to discover dataplane url',
387
+ 'dataplane service not found',
388
+ 'application not found',
389
+ 'dataplane url not found',
390
+ 'failed to download system',
391
+ 'not found',
392
+ 'external system'
393
+ ];
394
+
395
+ const timeout = isTimeoutResult(result);
396
+ const isValid = (!result.success || timeout) && (
397
+ timeout ||
398
+ validateError(output, expectedPatterns) ||
399
+ output.includes('not found') ||
400
+ output.includes('Failed') ||
401
+ output.includes('Error')
402
+ );
403
+
404
+ return {
405
+ name: 'dataplane discovery',
406
+ success: isValid,
407
+ output: timeout ? `${output}\n[Command timed out - this indicates the command may be hanging]` : output,
408
+ expectedPatterns: timeout ? [...expectedPatterns, 'timeout'] : expectedPatterns
409
+ };
410
+ }
411
+
412
+ module.exports = {
413
+ testWizard,
414
+ testDownload,
415
+ testDelete,
416
+ testDatasourceDeploy,
417
+ testIntegration,
418
+ testDataplaneDiscovery
419
+ };
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Dataplane Down Test Suite
4
+ *
5
+ * Tests all commands that interact with dataplane when dataplane is unavailable.
6
+ * Validates that appropriate error messages are returned.
7
+ *
8
+ * @fileoverview Dataplane down error handling tests
9
+ * @author AI Fabrix Team
10
+ * @version 2.0.0
11
+ */
12
+ 'use strict';
13
+
14
+ const {
15
+ logInfo,
16
+ logSuccess,
17
+ logError,
18
+ logWarn
19
+ } = require('./test-dataplane-down-helpers');
20
+ const {
21
+ testWizard,
22
+ testDownload,
23
+ testDelete,
24
+ testDatasourceDeploy,
25
+ testIntegration,
26
+ testDataplaneDiscovery
27
+ } = require('./test-dataplane-down-tests');
28
+
29
+ const INVALID_DATAPLANE_URL = 'http://localhost:9999';
30
+ const CONTROLLER_URL = process.env.CONTROLLER_URL || 'http://localhost:3110';
31
+ const ENVIRONMENT = process.env.ENVIRONMENT || 'miso';
32
+
33
+ /**
34
+ * Displays failed test details
35
+ * @function displayFailedTestDetails
36
+ * @param {Array} failedTests - Failed test results
37
+ * @returns {void}
38
+ */
39
+ function displayFailedTestDetails(failedTests) {
40
+ if (failedTests.length === 0) {
41
+ return;
42
+ }
43
+
44
+ logError('\nFailed Tests:');
45
+ for (const test of failedTests) {
46
+ logError(` - ${test.name}`);
47
+ if (test.output) {
48
+ const outputPreview = test.output.length > 500 ? test.output.substring(0, 500) + '...' : test.output;
49
+ logWarn(` Output: ${outputPreview}`);
50
+ }
51
+ if (test.error) {
52
+ logWarn(` Error: ${test.error}`);
53
+ }
54
+ if (test.expectedPatterns) {
55
+ logWarn(` Expected patterns: ${test.expectedPatterns.join(', ')}`);
56
+ }
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Displays test results summary
62
+ * @function displaySummary
63
+ * @param {Array} results - Test results
64
+ * @returns {void}
65
+ */
66
+ function displaySummary(results) {
67
+ logInfo('\n' + '='.repeat(60));
68
+ logInfo('Test Summary');
69
+ logInfo('='.repeat(60));
70
+
71
+ const passed = results.filter(r => r.success).length;
72
+ const failed = results.filter(r => !r.success).length;
73
+
74
+ logInfo(`Total tests: ${results.length}`);
75
+ logSuccess(`Passed: ${passed}`);
76
+ if (failed > 0) {
77
+ logError(`Failed: ${failed}`);
78
+ }
79
+
80
+ const failedTests = results.filter(r => !r.success);
81
+ displayFailedTestDetails(failedTests);
82
+
83
+ logInfo('='.repeat(60));
84
+ }
85
+
86
+ /**
87
+ * Runs all test cases
88
+ * @async
89
+ * @function runTests
90
+ * @returns {Promise<Array>} Test results
91
+ */
92
+ async function runTests() {
93
+ const tests = [
94
+ testWizard,
95
+ testDownload,
96
+ testDelete,
97
+ testDatasourceDeploy,
98
+ testIntegration,
99
+ testDataplaneDiscovery
100
+ ];
101
+
102
+ const results = [];
103
+
104
+ for (const testFn of tests) {
105
+ try {
106
+ const result = await testFn();
107
+ results.push(result);
108
+
109
+ if (result.success) {
110
+ logSuccess(`✓ ${result.name}: Error handling validated`);
111
+ } else {
112
+ logError(`✗ ${result.name}: Error handling failed`);
113
+ if (result.output) {
114
+ logWarn(` Output: ${result.output.substring(0, 200)}...`);
115
+ }
116
+ }
117
+ } catch (error) {
118
+ logError(`✗ ${testFn.name}: Unexpected error: ${error.message}`);
119
+ results.push({
120
+ name: testFn.name,
121
+ success: false,
122
+ error: error.message
123
+ });
124
+ }
125
+ }
126
+
127
+ return results;
128
+ }
129
+
130
+ /**
131
+ * Main test runner
132
+ * @async
133
+ * @function main
134
+ * @returns {Promise<void>} Resolves when tests complete
135
+ */
136
+ async function main() {
137
+ logInfo('='.repeat(60));
138
+ logInfo('Dataplane Down Error Handling Test Suite');
139
+ logInfo('='.repeat(60));
140
+ logInfo(`Invalid Dataplane URL: ${INVALID_DATAPLANE_URL}`);
141
+ logInfo(`Controller URL: ${CONTROLLER_URL}`);
142
+ logInfo(`Environment: ${ENVIRONMENT}`);
143
+ logInfo('='.repeat(60));
144
+
145
+ const results = await runTests();
146
+ displaySummary(results);
147
+
148
+ const failed = results.filter(r => !r.success).length;
149
+ if (failed > 0) {
150
+ process.exitCode = 1;
151
+ }
152
+ }
153
+
154
+ main().catch(error => {
155
+ logError(`Fatal error: ${error.message}`);
156
+ process.exitCode = 1;
157
+ });