stigmergy 1.2.0 → 1.2.6
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.
- package/LICENSE +18 -18
- package/README.md +28 -223
- package/STIGMERGY.md +61 -61
- package/docs/PROJECT_CONSTITUTION.md +433 -433
- package/docs/PROJECT_STRUCTURE_CURRENT.md +80 -80
- package/examples/calculator-example.js +72 -72
- package/examples/cline_usage_examples.md +364 -364
- package/examples/encryption-example.js +67 -67
- package/examples/json-parser-example.js +120 -120
- package/examples/json-validation-example.js +64 -64
- package/examples/rest-client-example.js +52 -52
- package/examples/rest_client_example.js +54 -54
- package/package.json +36 -15
- package/scripts/build.js +74 -74
- package/scripts/post-deployment-config.js +296 -296
- package/scripts/preinstall-check.js +173 -173
- package/scripts/publish.js +58 -268
- package/scripts/run-layered-tests.js +247 -0
- package/scripts/safe-install.js +139 -139
- package/scripts/simple-publish.js +57 -59
- package/src/adapters/claude/install_claude_integration.js +292 -0
- package/src/adapters/codebuddy/install_codebuddy_integration.js +349 -0
- package/src/adapters/codex/install_codex_integration.js +395 -0
- package/src/adapters/copilot/install_copilot_integration.js +716 -0
- package/src/adapters/gemini/install_gemini_integration.js +304 -0
- package/src/adapters/iflow/install_iflow_integration.js +304 -0
- package/src/adapters/qoder/install_qoder_integration.js +1090 -0
- package/src/adapters/qwen/install_qwen_integration.js +285 -0
- package/src/auth.js +173 -173
- package/src/auth_command.js +208 -208
- package/src/calculator.js +313 -313
- package/src/cli/router.js +417 -38
- package/src/core/cache_cleaner.js +767 -744
- package/src/core/cli_help_analyzer.js +680 -674
- package/src/core/cli_parameter_handler.js +132 -127
- package/src/core/cli_tools.js +89 -89
- package/src/core/coordination/index.js +16 -16
- package/src/core/coordination/nodejs/AdapterManager.js +102 -89
- package/src/core/coordination/nodejs/CLCommunication.js +132 -124
- package/src/core/coordination/nodejs/CLIIntegrationManager.js +272 -236
- package/src/core/coordination/nodejs/HealthChecker.js +76 -77
- package/src/core/coordination/nodejs/HookDeploymentManager.js +263 -190
- package/src/core/coordination/nodejs/StatisticsCollector.js +71 -71
- package/src/core/coordination/nodejs/index.js +90 -72
- package/src/core/coordination/nodejs/utils/Logger.js +29 -29
- package/src/core/enhanced_installer.js +479 -456
- package/src/core/enhanced_uninstaller.js +638 -618
- package/src/core/error_handler.js +406 -406
- package/src/core/installer.js +815 -294
- package/src/core/memory_manager.js +83 -83
- package/src/core/rest_client.js +160 -160
- package/src/core/smart_router.js +249 -146
- package/src/core/upgrade_manager.js +76 -59
- package/src/data_encryption.js +143 -143
- package/src/data_structures.js +440 -440
- package/src/deploy.js +55 -55
- package/src/index.js +30 -30
- package/src/test/cli-availability-checker.js +194 -0
- package/src/test/test-environment.js +289 -0
- package/src/utils/helpers.js +35 -35
- package/src/utils.js +921 -915
- package/src/weatherProcessor.js +228 -228
- package/test/cache-cleaner-implemented.test.js +0 -328
- package/test/cache-cleaner.test.js +0 -390
- package/test/calculator.test.js +0 -215
- package/test/collision-test.js +0 -26
- package/test/comprehensive-enhanced-features.test.js +0 -252
- package/test/comprehensive-execution-test.js +0 -428
- package/test/conflict-prevention-test.js +0 -95
- package/test/cross-cli-detection-test.js +0 -33
- package/test/csv-processing-test.js +0 -36
- package/test/deploy-hooks-test.js +0 -250
- package/test/e2e/claude-cli-test.js +0 -128
- package/test/e2e/collaboration-test.js +0 -75
- package/test/e2e/comprehensive-test.js +0 -431
- package/test/e2e/error-handling-test.js +0 -90
- package/test/e2e/individual-tool-test.js +0 -143
- package/test/e2e/other-cli-test.js +0 -130
- package/test/e2e/qoder-cli-test.js +0 -128
- package/test/e2e/run-e2e-tests.js +0 -73
- package/test/e2e/test-data.js +0 -88
- package/test/e2e/test-utils.js +0 -222
- package/test/encryption-simple-test.js +0 -110
- package/test/encryption.test.js +0 -129
- package/test/enhanced-main-alignment.test.js +0 -298
- package/test/enhanced-uninstaller-implemented.test.js +0 -271
- package/test/enhanced-uninstaller.test.js +0 -284
- package/test/error-handling-test.js +0 -341
- package/test/fibonacci.test.js +0 -178
- package/test/final-deploy-test.js +0 -221
- package/test/final-install-test.js +0 -226
- package/test/hash-table-demo.js +0 -33
- package/test/hash-table-test.js +0 -26
- package/test/hash_table_test.js +0 -114
- package/test/hook-system-integration-test.js +0 -307
- package/test/iflow-integration-test.js +0 -292
- package/test/improved-install-test.js +0 -362
- package/test/install-command-test.js +0 -370
- package/test/json-parser-test.js +0 -161
- package/test/json-validation-test.js +0 -164
- package/test/natural-language-skills-test.js +0 -320
- package/test/nl-integration-test.js +0 -179
- package/test/parameter-parsing-test.js +0 -143
- package/test/plugin-deployment-test.js +0 -316
- package/test/postinstall-test.js +0 -269
- package/test/python-plugins-test.js +0 -259
- package/test/real-test.js +0 -435
- package/test/remaining-adapters-test.js +0 -256
- package/test/rest-client-test.js +0 -56
- package/test/rest_client.test.js +0 -85
- package/test/safe-installation-cleaner.test.js +0 -343
- package/test/simple-iflow-hook-test.js +0 -137
- package/test/stigmergy-upgrade-test.js +0 -243
- package/test/system-compatibility-test.js +0 -467
- package/test/tdd-deploy-fix-test.js +0 -324
- package/test/tdd-fixes-test.js +0 -211
- package/test/third-party-skills-test.js +0 -321
- package/test/tool-selection-integration-test.js +0 -158
- package/test/unit/calculator-full.test.js +0 -191
- package/test/unit/calculator-simple.test.js +0 -96
- package/test/unit/calculator.test.js +0 -97
- package/test/unit/cli-scanner.test.js +0 -291
- package/test/unit/cli_parameter_handler.test.js +0 -116
- package/test/unit/cross-cli-executor.test.js +0 -399
- package/test/weather-processor.test.js +0 -104
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Python Plugins Test Suite
|
|
5
|
-
* This test verifies that all Python-based plugins and adapters are functional
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const { spawnSync } = require('child_process');
|
|
11
|
-
const os = require('os');
|
|
12
|
-
|
|
13
|
-
class PythonPluginsTest {
|
|
14
|
-
constructor() {
|
|
15
|
-
this.testResults = [];
|
|
16
|
-
this.stigmergyAssetsDir = path.join(os.homedir(), '.stigmergy', 'assets', 'adapters');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async runTests() {
|
|
20
|
-
console.log('==============================================');
|
|
21
|
-
console.log('PYTHON PLUGINS TEST SUITE');
|
|
22
|
-
console.log('==============================================\n');
|
|
23
|
-
|
|
24
|
-
// Test 1: Check Python availability
|
|
25
|
-
await this.testPythonAvailability();
|
|
26
|
-
|
|
27
|
-
// Test 2: Check adapter directories
|
|
28
|
-
await this.testAdapterDirectories();
|
|
29
|
-
|
|
30
|
-
// Test 3: Test installation scripts
|
|
31
|
-
await this.testInstallationScripts();
|
|
32
|
-
|
|
33
|
-
// Test 4: Test adapter functionality
|
|
34
|
-
await this.testAdapterFunctionality();
|
|
35
|
-
|
|
36
|
-
this.generateReport();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async testPythonAvailability() {
|
|
40
|
-
console.log('TEST 1: Python Availability');
|
|
41
|
-
console.log('--------------------------');
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const result = spawnSync('python', ['--version'], {
|
|
45
|
-
encoding: 'utf8',
|
|
46
|
-
timeout: 5000
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
if (result.status === 0) {
|
|
50
|
-
console.log(` ✅ Python available: ${result.stdout.trim()}`);
|
|
51
|
-
this.testResults.push({
|
|
52
|
-
name: 'Python Availability',
|
|
53
|
-
passed: true,
|
|
54
|
-
details: result.stdout.trim()
|
|
55
|
-
});
|
|
56
|
-
} else {
|
|
57
|
-
console.log(` ❌ Python not available: ${result.stderr}`);
|
|
58
|
-
this.testResults.push({
|
|
59
|
-
name: 'Python Availability',
|
|
60
|
-
passed: false,
|
|
61
|
-
details: result.stderr
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.log(` ❌ Python test failed: ${error.message}`);
|
|
66
|
-
this.testResults.push({
|
|
67
|
-
name: 'Python Availability',
|
|
68
|
-
passed: false,
|
|
69
|
-
details: error.message
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
console.log('');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async testAdapterDirectories() {
|
|
76
|
-
console.log('TEST 2: Adapter Directories');
|
|
77
|
-
console.log('--------------------------');
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
if (!fs.existsSync(this.stigmergyAssetsDir)) {
|
|
81
|
-
console.log(` ❌ Assets directory not found: ${this.stigmergyAssetsDir}`);
|
|
82
|
-
this.testResults.push({
|
|
83
|
-
name: 'Adapter Directories',
|
|
84
|
-
passed: false,
|
|
85
|
-
details: `Assets directory not found: ${this.stigmergyAssetsDir}`
|
|
86
|
-
});
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const adapterDirs = fs.readdirSync(this.stigmergyAssetsDir);
|
|
91
|
-
console.log(` ✅ Found ${adapterDirs.length} adapter directories:`);
|
|
92
|
-
adapterDirs.forEach(dir => console.log(` - ${dir}`));
|
|
93
|
-
|
|
94
|
-
this.testResults.push({
|
|
95
|
-
name: 'Adapter Directories',
|
|
96
|
-
passed: true,
|
|
97
|
-
details: `Found ${adapterDirs.length} adapter directories`
|
|
98
|
-
});
|
|
99
|
-
} catch (error) {
|
|
100
|
-
console.log(` ❌ Adapter directories test failed: ${error.message}`);
|
|
101
|
-
this.testResults.push({
|
|
102
|
-
name: 'Adapter Directories',
|
|
103
|
-
passed: false,
|
|
104
|
-
details: error.message
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
console.log('');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async testInstallationScripts() {
|
|
111
|
-
console.log('TEST 3: Installation Scripts');
|
|
112
|
-
console.log('----------------------------');
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
const adapterDirs = fs.readdirSync(this.stigmergyAssetsDir);
|
|
116
|
-
let scriptCount = 0;
|
|
117
|
-
let workingScripts = 0;
|
|
118
|
-
|
|
119
|
-
for (const dir of adapterDirs) {
|
|
120
|
-
const adapterDir = path.join(this.stigmergyAssetsDir, dir);
|
|
121
|
-
const installScript = path.join(adapterDir, `install_${dir}_integration.py`);
|
|
122
|
-
|
|
123
|
-
if (fs.existsSync(installScript)) {
|
|
124
|
-
scriptCount++;
|
|
125
|
-
console.log(` Found: ${dir} installation script`);
|
|
126
|
-
|
|
127
|
-
// Test script help functionality
|
|
128
|
-
try {
|
|
129
|
-
const result = spawnSync('python', [installScript, '--help'], {
|
|
130
|
-
encoding: 'utf8',
|
|
131
|
-
timeout: 10000
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
if (result.status === 0 || result.stderr.includes('usage:') || result.stdout.includes('usage:')) {
|
|
135
|
-
console.log(` ✅ ${dir} script works`);
|
|
136
|
-
workingScripts++;
|
|
137
|
-
} else {
|
|
138
|
-
console.log(` ⚠️ ${dir} script has issues`);
|
|
139
|
-
}
|
|
140
|
-
} catch (scriptError) {
|
|
141
|
-
console.log(` ⚠️ ${dir} script test failed: ${scriptError.message}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
console.log(`\n Found ${scriptCount} installation scripts, ${workingScripts} working`);
|
|
147
|
-
this.testResults.push({
|
|
148
|
-
name: 'Installation Scripts',
|
|
149
|
-
passed: workingScripts > 0,
|
|
150
|
-
details: `Found ${scriptCount} scripts, ${workingScripts} working`
|
|
151
|
-
});
|
|
152
|
-
} catch (error) {
|
|
153
|
-
console.log(` ❌ Installation scripts test failed: ${error.message}`);
|
|
154
|
-
this.testResults.push({
|
|
155
|
-
name: 'Installation Scripts',
|
|
156
|
-
passed: false,
|
|
157
|
-
details: error.message
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
console.log('');
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async testAdapterFunctionality() {
|
|
164
|
-
console.log('TEST 4: Adapter Functionality');
|
|
165
|
-
console.log('----------------------------');
|
|
166
|
-
|
|
167
|
-
const keyAdapters = ['iflow', 'claude', 'qoder'];
|
|
168
|
-
let testedAdapters = 0;
|
|
169
|
-
let workingAdapters = 0;
|
|
170
|
-
|
|
171
|
-
for (const adapter of keyAdapters) {
|
|
172
|
-
const adapterDir = path.join(this.stigmergyAssetsDir, adapter);
|
|
173
|
-
const installScript = path.join(adapterDir, `install_${adapter}_integration.py`);
|
|
174
|
-
|
|
175
|
-
if (fs.existsSync(installScript)) {
|
|
176
|
-
testedAdapters++;
|
|
177
|
-
console.log(` Testing ${adapter} adapter...`);
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
// Test status command for adapters that support it
|
|
181
|
-
const result = spawnSync('python', [installScript, 'status'], {
|
|
182
|
-
encoding: 'utf8',
|
|
183
|
-
timeout: 15000
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
if (result.status === 0) {
|
|
187
|
-
console.log(` ✅ ${adapter} adapter functional`);
|
|
188
|
-
workingAdapters++;
|
|
189
|
-
} else {
|
|
190
|
-
// Try alternative command
|
|
191
|
-
const helpResult = spawnSync('python', [installScript, '--help'], {
|
|
192
|
-
encoding: 'utf8',
|
|
193
|
-
timeout: 10000
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
if (helpResult.status === 0) {
|
|
197
|
-
console.log(` ✅ ${adapter} adapter accessible (help works)`);
|
|
198
|
-
workingAdapters++;
|
|
199
|
-
} else {
|
|
200
|
-
console.log(` ⚠️ ${adapter} adapter has issues`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
} catch (adapterError) {
|
|
204
|
-
console.log(` ⚠️ ${adapter} adapter test failed: ${adapterError.message}`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
console.log(`\n Tested ${testedAdapters} key adapters, ${workingAdapters} functional`);
|
|
210
|
-
this.testResults.push({
|
|
211
|
-
name: 'Adapter Functionality',
|
|
212
|
-
passed: workingAdapters > 0,
|
|
213
|
-
details: `Tested ${testedAdapters} adapters, ${workingAdapters} functional`
|
|
214
|
-
});
|
|
215
|
-
console.log('');
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
generateReport() {
|
|
219
|
-
console.log('==============================================');
|
|
220
|
-
console.log('PYTHON PLUGINS TEST REPORT');
|
|
221
|
-
console.log('==============================================\n');
|
|
222
|
-
|
|
223
|
-
const passedTests = this.testResults.filter(t => t.passed).length;
|
|
224
|
-
const totalTests = this.testResults.length;
|
|
225
|
-
|
|
226
|
-
console.log(`📊 TEST RESULTS: ${passedTests}/${totalTests} tests passed\n`);
|
|
227
|
-
|
|
228
|
-
if (passedTests === totalTests) {
|
|
229
|
-
console.log('✅ ALL PYTHON PLUGIN TESTS PASSED');
|
|
230
|
-
console.log('🎉 Python plugins are fully functional and ready for use!\n');
|
|
231
|
-
} else if (passedTests > 0) {
|
|
232
|
-
console.log('⚠️ SOME PYTHON PLUGIN TESTS PASSED');
|
|
233
|
-
console.log('🔧 Python plugins have partial functionality\n');
|
|
234
|
-
} else {
|
|
235
|
-
console.log('❌ NO PYTHON PLUGIN TESTS PASSED');
|
|
236
|
-
console.log('🚨 Python plugins require attention\n');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
console.log('📋 DETAILED RESULTS:');
|
|
240
|
-
this.testResults.forEach((test, index) => {
|
|
241
|
-
const status = test.passed ? '✅' : '❌';
|
|
242
|
-
console.log(`${index + 1}. ${status} ${test.name}: ${test.details}`);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
console.log('\n🎯 RECOMMENDATIONS:');
|
|
246
|
-
console.log('1. Ensure all Python installation scripts are executable');
|
|
247
|
-
console.log('2. Verify Python dependencies are installed');
|
|
248
|
-
console.log('3. Test adapter integration with actual AI tools');
|
|
249
|
-
console.log('4. Monitor for encoding issues in cross-platform environments');
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Run tests
|
|
254
|
-
if (require.main === module) {
|
|
255
|
-
const tester = new PythonPluginsTest();
|
|
256
|
-
tester.runTests();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
module.exports = PythonPluginsTest;
|
package/test/real-test.js
DELETED
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Real Test Runner - TDD Implementation Validation
|
|
3
|
-
* 真实测试,无Mock,ANSI编码,Node.js优先
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
// 导入我们的实现
|
|
10
|
-
const CLIScanner = require('../src/core/cli-scanner');
|
|
11
|
-
const CrossCLIExecutor = require('../src/core/cross-cli-executor');
|
|
12
|
-
|
|
13
|
-
// ANSI安全输出
|
|
14
|
-
function safeLog(message) {
|
|
15
|
-
process.stdout.write(`${message}\n`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// 简单的测试框架
|
|
19
|
-
class RealTestRunner {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.results = {
|
|
22
|
-
passed: 0,
|
|
23
|
-
failed: 0,
|
|
24
|
-
skipped: 0,
|
|
25
|
-
errors: 0
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async test(name, testFn) {
|
|
30
|
-
try {
|
|
31
|
-
safeLog(`Testing: ${name}`);
|
|
32
|
-
await testFn();
|
|
33
|
-
this.results.passed++;
|
|
34
|
-
safeLog(`[PASS] ${name}`);
|
|
35
|
-
} catch (error) {
|
|
36
|
-
this.results.failed++;
|
|
37
|
-
safeLog(`[FAIL] ${name}`);
|
|
38
|
-
safeLog(` Error: ${error.message}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
skip(name, reason) {
|
|
43
|
-
this.results.skipped++;
|
|
44
|
-
safeLog(`[SKIP] ${name} - ${reason}`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
error(name, error) {
|
|
48
|
-
this.results.errors++;
|
|
49
|
-
safeLog(`[ERROR] ${name}`);
|
|
50
|
-
safeLog(` ${error.message}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
printSummary() {
|
|
54
|
-
const total = this.results.passed + this.results.failed + this.results.skipped + this.results.errors;
|
|
55
|
-
safeLog(`\n=== Test Summary ===`);
|
|
56
|
-
safeLog(`Total: ${total}`);
|
|
57
|
-
safeLog(`Passed: ${this.results.passed}`);
|
|
58
|
-
safeLog(`Failed: ${this.results.failed}`);
|
|
59
|
-
safeLog(`Skipped: ${this.results.skipped}`);
|
|
60
|
-
safeLog(`Errors: ${this.results.errors}`);
|
|
61
|
-
safeLog(`Success Rate: ${((this.results.passed / total) * 100).toFixed(1)}%`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 测试套件
|
|
66
|
-
async function runRealTests() {
|
|
67
|
-
safeLog('Starting Real TDD Tests - No Mocks, ANSI Encoding Only');
|
|
68
|
-
safeLog('='.repeat(60));
|
|
69
|
-
|
|
70
|
-
const runner = new RealTestRunner();
|
|
71
|
-
|
|
72
|
-
// 1. CLI扫描器测试
|
|
73
|
-
safeLog('\n--- CLI Scanner Tests ---');
|
|
74
|
-
|
|
75
|
-
await runner.test('Scanner initialization', () => {
|
|
76
|
-
const scanner = new CLIScanner();
|
|
77
|
-
if (!scanner) {
|
|
78
|
-
throw new Error('Scanner failed to initialize');
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
await runner.test('Detect Node.js CLI', async () => {
|
|
83
|
-
const scanner = new CLIScanner();
|
|
84
|
-
const result = await scanner.scanForCLI('node', { timeout: 5000 });
|
|
85
|
-
|
|
86
|
-
if (!result.available) {
|
|
87
|
-
throw new Error('Node.js should be available');
|
|
88
|
-
}
|
|
89
|
-
if (!result.version) {
|
|
90
|
-
throw new Error('Node.js version should be detected');
|
|
91
|
-
}
|
|
92
|
-
if (!result.path) {
|
|
93
|
-
throw new Error('Node.js path should be detected');
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
await runner.test('Detect NPM CLI', async () => {
|
|
98
|
-
const scanner = new CLIScanner();
|
|
99
|
-
const result = await scanner.scanForCLI('npm', { timeout: 5000 });
|
|
100
|
-
|
|
101
|
-
if (!result.available) {
|
|
102
|
-
throw new Error('NPM should be available');
|
|
103
|
-
}
|
|
104
|
-
if (!result.version) {
|
|
105
|
-
throw new Error('NPM version should be detected');
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
await runner.test('Handle non-existent CLI', async () => {
|
|
110
|
-
const scanner = new CLIScanner();
|
|
111
|
-
const result = await scanner.scanForCLI('non-existent-cli-12345', { timeout: 3000 });
|
|
112
|
-
|
|
113
|
-
if (result.available) {
|
|
114
|
-
throw new Error('Non-existent CLI should not be available');
|
|
115
|
-
}
|
|
116
|
-
if (!result.error) {
|
|
117
|
-
throw new Error('Should include error message');
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
await runner.test('Batch CLI detection', async () => {
|
|
122
|
-
const scanner = new CLIScanner();
|
|
123
|
-
const results = await scanner.detectInstalledCLIs(['node', 'npm', 'non-existent-cli'], { timeout: 5000 });
|
|
124
|
-
|
|
125
|
-
if (results.size !== 3) {
|
|
126
|
-
throw new Error('Should return results for all 3 CLIs');
|
|
127
|
-
}
|
|
128
|
-
if (!results.get('node').available) {
|
|
129
|
-
throw new Error('Node should be available');
|
|
130
|
-
}
|
|
131
|
-
if (!results.get('npm').available) {
|
|
132
|
-
throw new Error('NPM should be available');
|
|
133
|
-
}
|
|
134
|
-
if (results.get('non-existent-cli').available) {
|
|
135
|
-
throw new Error('Non-existent CLI should not be available');
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
await runner.test('CLI validation', () => {
|
|
140
|
-
const scanner = new CLIScanner();
|
|
141
|
-
|
|
142
|
-
if (!scanner.validateCLIExecutable('node')) {
|
|
143
|
-
throw new Error('Node should be valid executable');
|
|
144
|
-
}
|
|
145
|
-
if (scanner.validateCLIExecutable('')) {
|
|
146
|
-
throw new Error('Empty string should not be valid');
|
|
147
|
-
}
|
|
148
|
-
if (scanner.validateCLIExecutable('non-existent-command-12345')) {
|
|
149
|
-
throw new Error('Random string should not be valid executable');
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// 2. 跨CLI执行器测试
|
|
154
|
-
safeLog('\n--- Cross-CLI Executor Tests ---');
|
|
155
|
-
|
|
156
|
-
await runner.test('Executor initialization', () => {
|
|
157
|
-
const executor = new CrossCLIExecutor();
|
|
158
|
-
if (!executor) {
|
|
159
|
-
throw new Error('Executor failed to initialize');
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
await runner.test('Execute Node.js command', async () => {
|
|
164
|
-
const executor = new CrossCLIExecutor();
|
|
165
|
-
const result = await executor.executeCommand('node', ['--version'], { timeout: 5000 });
|
|
166
|
-
|
|
167
|
-
if (!result.success) {
|
|
168
|
-
throw new Error('Node version command should succeed');
|
|
169
|
-
}
|
|
170
|
-
if (!result.stdout) {
|
|
171
|
-
throw new Error('Should have stdout output');
|
|
172
|
-
}
|
|
173
|
-
if (result.exitCode !== 0) {
|
|
174
|
-
throw new Error('Exit code should be 0');
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
await runner.test('Execute NPM command', async () => {
|
|
179
|
-
const executor = new CrossCLIExecutor();
|
|
180
|
-
const result = await executor.executeCommand('npm', ['--version'], { timeout: 5000 });
|
|
181
|
-
|
|
182
|
-
if (!result.success) {
|
|
183
|
-
throw new Error('NPM version command should succeed');
|
|
184
|
-
}
|
|
185
|
-
if (!result.stdout) {
|
|
186
|
-
throw new Error('Should have stdout output');
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
await runner.test('Handle command timeout', async () => {
|
|
191
|
-
const executor = new CrossCLIExecutor();
|
|
192
|
-
const startTime = Date.now();
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
await executor.executeCommand('node', ['-e', 'setTimeout(() => {}, 5000)'], { timeout: 2000 });
|
|
196
|
-
throw new Error('Should have thrown timeout error');
|
|
197
|
-
} catch (error) {
|
|
198
|
-
const elapsed = Date.now() - startTime;
|
|
199
|
-
if (elapsed > 10000) { // 10秒安全边界
|
|
200
|
-
throw new Error('Timeout should have occurred quickly');
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
await runner.test('Handle non-existent command', async () => {
|
|
206
|
-
const executor = new CrossCLIExecutor();
|
|
207
|
-
const result = await executor.executeCommand('non-existent-command-12345', [], { timeout: 3000 });
|
|
208
|
-
|
|
209
|
-
if (result.success) {
|
|
210
|
-
throw new Error('Non-existent command should fail');
|
|
211
|
-
}
|
|
212
|
-
if (!result.error) {
|
|
213
|
-
throw new Error('Should include error message');
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
await runner.test('Parameter validation', () => {
|
|
218
|
-
const executor = new CrossCLIExecutor();
|
|
219
|
-
|
|
220
|
-
// 有效参数
|
|
221
|
-
const validResult = executor.validateExecutionParams('claude', 'gemini', 'test task');
|
|
222
|
-
if (!validResult.valid) {
|
|
223
|
-
throw new Error('Valid parameters should pass');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// 无效参数
|
|
227
|
-
const invalidResult1 = executor.validateExecutionParams('', 'gemini', 'test task');
|
|
228
|
-
if (invalidResult1.valid) {
|
|
229
|
-
throw new Error('Empty source CLI should be invalid');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const invalidResult2 = executor.validateExecutionParams('claude', '', 'test task');
|
|
233
|
-
if (invalidResult2.valid) {
|
|
234
|
-
throw new Error('Empty target CLI should be invalid');
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const invalidResult3 = executor.validateExecutionParams('claude', 'gemini', '');
|
|
238
|
-
if (invalidResult3.valid) {
|
|
239
|
-
throw new Error('Empty task should be invalid');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const invalidResult4 = executor.validateExecutionParams('claude', 'claude', 'test task');
|
|
243
|
-
if (invalidResult4.valid) {
|
|
244
|
-
throw new Error('Same source and target should be invalid');
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
// 3. 跨CLI协作测试
|
|
249
|
-
safeLog('\n--- Cross-CLI Collaboration Tests ---');
|
|
250
|
-
|
|
251
|
-
await runner.test('Dry run cross-CLI execution', async () => {
|
|
252
|
-
const executor = new CrossCLIExecutor();
|
|
253
|
-
const result = await executor.executeCrossCLI('claude', 'gemini', 'translate "hello world"', {
|
|
254
|
-
dryRun: true,
|
|
255
|
-
timeout: 5000
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
if (!result.success) {
|
|
259
|
-
throw new Error('Dry run should succeed');
|
|
260
|
-
}
|
|
261
|
-
if (!result.sourceCLI || result.sourceCLI !== 'claude') {
|
|
262
|
-
throw new Error('Should preserve source CLI');
|
|
263
|
-
}
|
|
264
|
-
if (!result.targetCLI || result.targetCLI !== 'gemini') {
|
|
265
|
-
throw new Error('Should preserve target CLI');
|
|
266
|
-
}
|
|
267
|
-
if (!result.executionId) {
|
|
268
|
-
throw new Error('Should generate execution ID');
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// 4. 性能和内存测试
|
|
273
|
-
safeLog('\n--- Performance Tests ---');
|
|
274
|
-
|
|
275
|
-
await runner.test('Concurrent command execution', async () => {
|
|
276
|
-
const executor = new CrossCLIExecutor();
|
|
277
|
-
const startTime = Date.now();
|
|
278
|
-
|
|
279
|
-
const commands = [
|
|
280
|
-
executor.executeCommand('node', ['--version']),
|
|
281
|
-
executor.executeCommand('npm', ['--version']),
|
|
282
|
-
executor.executeCommand('node', ['-e', 'console.log("test")'])
|
|
283
|
-
];
|
|
284
|
-
|
|
285
|
-
const results = await Promise.all(commands);
|
|
286
|
-
const elapsed = Date.now() - startTime;
|
|
287
|
-
|
|
288
|
-
if (results.length !== 3) {
|
|
289
|
-
throw new Error('Should execute all 3 commands');
|
|
290
|
-
}
|
|
291
|
-
if (!results.every(r => r.success)) {
|
|
292
|
-
throw new Error('All commands should succeed');
|
|
293
|
-
}
|
|
294
|
-
if (elapsed > 15000) { // 15秒安全边界
|
|
295
|
-
throw new Error('Should complete within reasonable time');
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
await runner.test('Memory usage', async () => {
|
|
300
|
-
const initialMemory = process.memoryUsage().heapUsed;
|
|
301
|
-
const executor = new CrossCLIExecutor();
|
|
302
|
-
|
|
303
|
-
// 执行多个命令测试内存泄漏
|
|
304
|
-
for (let i = 0; i < 20; i++) {
|
|
305
|
-
await executor.executeCommand('node', ['--version']);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// 强制垃圾回收(如果可用)
|
|
309
|
-
if (global.gc) {
|
|
310
|
-
global.gc();
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const finalMemory = process.memoryUsage().heapUsed;
|
|
314
|
-
const memoryIncrease = finalMemory - initialMemory;
|
|
315
|
-
|
|
316
|
-
// 内存增长应该控制在合理范围内
|
|
317
|
-
const maxAcceptableIncrease = 50 * 1024 * 1024; // 50MB
|
|
318
|
-
if (memoryIncrease > maxAcceptableIncrease) {
|
|
319
|
-
throw new Error(`Memory increased too much: ${Math.round(memoryIncrease / 1024 / 1024)}MB`);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// 5. 平台特定测试
|
|
324
|
-
safeLog('\n--- Platform-Specific Tests ---');
|
|
325
|
-
|
|
326
|
-
if (process.platform === 'win32') {
|
|
327
|
-
await runner.test('Windows command execution', async () => {
|
|
328
|
-
const executor = new CrossCLIExecutor();
|
|
329
|
-
const result = await executor.executeCommand('cmd', ['/c', 'echo test'], { timeout: 5000 });
|
|
330
|
-
|
|
331
|
-
if (!result.success) {
|
|
332
|
-
throw new Error('Windows cmd should succeed');
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
} else {
|
|
336
|
-
await runner.test('Unix command execution', async () => {
|
|
337
|
-
const executor = new CrossCLIExecutor();
|
|
338
|
-
const result = await executor.executeCommand('echo', ['test'], { timeout: 5000 });
|
|
339
|
-
|
|
340
|
-
if (!result.success) {
|
|
341
|
-
throw new Error('Unix echo should succeed');
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// 6. 错误处理和边界条件测试
|
|
347
|
-
safeLog('\n--- Error Handling Tests ---');
|
|
348
|
-
|
|
349
|
-
await runner.test('Invalid input handling', async () => {
|
|
350
|
-
const executor = new CrossCLIExecutor();
|
|
351
|
-
|
|
352
|
-
// 测试无效命令
|
|
353
|
-
try {
|
|
354
|
-
await executor.executeCommand('', []);
|
|
355
|
-
throw new Error('Empty command should throw error');
|
|
356
|
-
} catch (error) {
|
|
357
|
-
if (!error.message.includes('Invalid command')) {
|
|
358
|
-
throw new Error('Should have specific error message');
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
await runner.test('Statistics tracking', async () => {
|
|
364
|
-
const executor = new CrossCLIExecutor();
|
|
365
|
-
const initialStats = executor.getStats();
|
|
366
|
-
|
|
367
|
-
// 执行一些命令
|
|
368
|
-
await executor.executeCommand('node', ['--version']);
|
|
369
|
-
await executor.executeCommand('non-existent-command', []);
|
|
370
|
-
|
|
371
|
-
const finalStats = executor.getStats();
|
|
372
|
-
if (finalStats.totalExecutions <= initialStats.totalExecutions) {
|
|
373
|
-
throw new Error('Statistics should track executions');
|
|
374
|
-
}
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
// 打印总结
|
|
378
|
-
runner.printSummary();
|
|
379
|
-
|
|
380
|
-
// 7. 集成测试
|
|
381
|
-
safeLog('\n--- Integration Tests ---');
|
|
382
|
-
|
|
383
|
-
await runner.test('End-to-end scanner and executor integration', async () => {
|
|
384
|
-
const scanner = new CLIScanner();
|
|
385
|
-
const executor = new CrossCLIExecutor();
|
|
386
|
-
|
|
387
|
-
// 扫描可用的CLI
|
|
388
|
-
const scanResults = await scanner.detectInstalledCLIs(['node', 'npm']);
|
|
389
|
-
|
|
390
|
-
if (scanResults.size === 0) {
|
|
391
|
-
throw new Error('Should detect at least some CLI tools');
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// 使用检测到的CLI执行命令
|
|
395
|
-
for (const [cliName, cliInfo] of scanResults) {
|
|
396
|
-
if (cliInfo.available) {
|
|
397
|
-
const result = await executor.executeCommand(cliName, ['--version']);
|
|
398
|
-
if (!result.success) {
|
|
399
|
-
safeLog(`Warning: ${cliName} detected but failed to execute`);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
safeLog('\n=== All Real Tests Completed ===');
|
|
406
|
-
runner.printSummary();
|
|
407
|
-
|
|
408
|
-
return runner.results;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// 主执行函数
|
|
412
|
-
async function main() {
|
|
413
|
-
try {
|
|
414
|
-
const results = await runRealTests();
|
|
415
|
-
|
|
416
|
-
// 设置退出码
|
|
417
|
-
if (results.failed > 0 || results.errors > 0) {
|
|
418
|
-
process.exit(1);
|
|
419
|
-
} else {
|
|
420
|
-
process.exit(0);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
} catch (error) {
|
|
424
|
-
safeLog(`Fatal error during test execution: ${error.message}`);
|
|
425
|
-
safeLog(`Stack trace: ${error.stack}`);
|
|
426
|
-
process.exit(1);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// 如果直接运行此文件
|
|
431
|
-
if (require.main === module) {
|
|
432
|
-
main();
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
module.exports = { RealTestRunner, runRealTests };
|