molex-ftp-client 2.0.0 โ 2.2.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.
- package/CHANGELOG.md +34 -3
- package/README.md +138 -397
- package/lib/FTPClient.js +54 -5
- package/lib/commands.js +183 -111
- package/lib/connection.js +2 -7
- package/lib/performance.js +16 -67
- package/package.json +1 -1
- package/test-comprehensive.js +235 -0
- package/benchmark.js +0 -86
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
const FTPClient = require('./index.js');
|
|
2
|
+
|
|
3
|
+
// Test configuration
|
|
4
|
+
const CONFIG = {
|
|
5
|
+
host: '',
|
|
6
|
+
port: 21,
|
|
7
|
+
user: '',
|
|
8
|
+
password: ''
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const TEST_DIR = '/molex-ftp-testing';
|
|
12
|
+
|
|
13
|
+
// Test runner
|
|
14
|
+
async function runTests() {
|
|
15
|
+
const client = new FTPClient({
|
|
16
|
+
debug: true,
|
|
17
|
+
timeout: 30000
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
console.log('\n๐งช Starting FTP Client Comprehensive Test Suite\n');
|
|
21
|
+
console.log('=' .repeat(60));
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Test 1: Connect
|
|
25
|
+
console.log('\nโ
TEST 1: Connect to FTP server');
|
|
26
|
+
await client.connect(CONFIG);
|
|
27
|
+
console.log(` Connected to ${CONFIG.host}:${CONFIG.port}`);
|
|
28
|
+
|
|
29
|
+
// Test 2: Get current directory
|
|
30
|
+
console.log('\nโ
TEST 2: Get current working directory');
|
|
31
|
+
const currentDir = await client.pwd();
|
|
32
|
+
console.log(` Current directory: ${currentDir}`);
|
|
33
|
+
|
|
34
|
+
// Test 3: Create test directory
|
|
35
|
+
console.log(`\nโ
TEST 3: Create test directory ${TEST_DIR}`);
|
|
36
|
+
try {
|
|
37
|
+
await client.mkdir(TEST_DIR);
|
|
38
|
+
console.log(` Created ${TEST_DIR}`);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.log(` Directory already exists or error: ${err.message}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Test 4: Change to test directory
|
|
44
|
+
console.log(`\nโ
TEST 4: Change to test directory`);
|
|
45
|
+
await client.cd(TEST_DIR);
|
|
46
|
+
const newDir = await client.pwd();
|
|
47
|
+
console.log(` Changed to: ${newDir}`);
|
|
48
|
+
|
|
49
|
+
// Test 5: Upload a text file
|
|
50
|
+
console.log('\nโ
TEST 5: Upload text file');
|
|
51
|
+
const testContent = 'Hello from molex-ftp-client!\nTimestamp: ' + new Date().toISOString();
|
|
52
|
+
await client.upload(testContent, 'test-file.txt');
|
|
53
|
+
console.log(' Uploaded test-file.txt');
|
|
54
|
+
|
|
55
|
+
// Test 6: Upload with auto-directory creation
|
|
56
|
+
console.log('\nโ
TEST 6: Upload with auto-directory creation');
|
|
57
|
+
await client.upload('Nested file content', 'subdir/nested/deep.txt', true);
|
|
58
|
+
console.log(' Uploaded subdir/nested/deep.txt (created directories)');
|
|
59
|
+
|
|
60
|
+
// Test 7: Check if file exists
|
|
61
|
+
console.log('\nโ
TEST 7: Check if file exists');
|
|
62
|
+
const exists = await client.exists('test-file.txt');
|
|
63
|
+
console.log(` test-file.txt exists: ${exists}`);
|
|
64
|
+
|
|
65
|
+
// Test 8: Get file stats
|
|
66
|
+
console.log('\nโ
TEST 8: Get file statistics');
|
|
67
|
+
const stat = await client.stat('test-file.txt');
|
|
68
|
+
console.log(` Stats:`, stat);
|
|
69
|
+
|
|
70
|
+
// Test 9: Get file size
|
|
71
|
+
console.log('\nโ
TEST 9: Get file size');
|
|
72
|
+
const size = await client.size('test-file.txt');
|
|
73
|
+
console.log(` Size: ${size} bytes`);
|
|
74
|
+
|
|
75
|
+
// Test 10: Download file
|
|
76
|
+
console.log('\nโ
TEST 10: Download file');
|
|
77
|
+
const downloaded = await client.download('test-file.txt');
|
|
78
|
+
console.log(` Downloaded ${downloaded.length} bytes`);
|
|
79
|
+
console.log(` Content: ${downloaded.toString().substring(0, 50)}...`);
|
|
80
|
+
|
|
81
|
+
// Test 11: List directory
|
|
82
|
+
console.log('\nโ
TEST 11: List directory (raw)');
|
|
83
|
+
const listing = await client.list('.');
|
|
84
|
+
console.log(` Listing:\n${listing.split('\n').slice(0, 5).join('\n')}`);
|
|
85
|
+
|
|
86
|
+
// Test 12: List directory detailed
|
|
87
|
+
console.log('\nโ
TEST 12: List directory (detailed)');
|
|
88
|
+
const detailedListing = await client.listDetailed('.');
|
|
89
|
+
console.log(` Found ${detailedListing.length} items:`);
|
|
90
|
+
detailedListing.forEach(item => {
|
|
91
|
+
console.log(` - ${item.type === 'directory' ? '๐' : '๐'} ${item.name} (${item.permissions || 'N/A'})`);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Test 13: Rename file
|
|
95
|
+
console.log('\nโ
TEST 13: Rename file');
|
|
96
|
+
await client.rename('test-file.txt', 'renamed-file.txt');
|
|
97
|
+
console.log(' Renamed test-file.txt โ renamed-file.txt');
|
|
98
|
+
|
|
99
|
+
// Test 14: Get modified time
|
|
100
|
+
console.log('\nโ
TEST 14: Get file modification time');
|
|
101
|
+
try {
|
|
102
|
+
const modTime = await client.modifiedTime('renamed-file.txt');
|
|
103
|
+
console.log(` Modified: ${modTime}`);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.log(` Not supported or error: ${err.message}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Test 15: Create multiple directories
|
|
109
|
+
console.log('\nโ
TEST 15: Create nested directories');
|
|
110
|
+
await client.mkdir('test-dir-1');
|
|
111
|
+
await client.mkdir('test-dir-2');
|
|
112
|
+
await client.ensureDir('deep/nested/structure');
|
|
113
|
+
console.log(' Created test-dir-1, test-dir-2, and deep/nested/structure');
|
|
114
|
+
|
|
115
|
+
// Test 16: Upload file with Buffer
|
|
116
|
+
console.log('\nโ
TEST 16: Upload file using Buffer');
|
|
117
|
+
const buffer = Buffer.from('Binary content test', 'utf8');
|
|
118
|
+
await client.upload(buffer, 'test-dir-1/buffer-test.bin');
|
|
119
|
+
console.log(' Uploaded buffer-test.bin to test-dir-1');
|
|
120
|
+
|
|
121
|
+
// Test 17: Download with stream
|
|
122
|
+
console.log('\nโ
TEST 17: Download using stream');
|
|
123
|
+
const { PassThrough } = require('stream');
|
|
124
|
+
const stream = new PassThrough();
|
|
125
|
+
const chunks = [];
|
|
126
|
+
stream.on('data', chunk => chunks.push(chunk));
|
|
127
|
+
const bytes = await client.downloadStream('renamed-file.txt', stream);
|
|
128
|
+
console.log(` Downloaded ${bytes} bytes via stream`);
|
|
129
|
+
|
|
130
|
+
// Test 17b: Large file upload/download performance test
|
|
131
|
+
console.log('\nโ
TEST 17b: Large file performance test');
|
|
132
|
+
const largeData = Buffer.alloc(1024 * 1024, 'x'); // 1MB file
|
|
133
|
+
console.log(` Uploading 1MB file...`);
|
|
134
|
+
const uploadStart = Date.now();
|
|
135
|
+
await client.upload(largeData, 'large-test.bin');
|
|
136
|
+
const uploadTime = Date.now() - uploadStart;
|
|
137
|
+
console.log(` Upload: ${(largeData.length / uploadTime / 1024).toFixed(2)} MB/s (${uploadTime}ms)`);
|
|
138
|
+
|
|
139
|
+
console.log(` Downloading 1MB file...`);
|
|
140
|
+
const downloadStart = Date.now();
|
|
141
|
+
const largeDownload = await client.download('large-test.bin');
|
|
142
|
+
const downloadTime = Date.now() - downloadStart;
|
|
143
|
+
console.log(` Download: ${(largeDownload.length / downloadTime / 1024).toFixed(2)} MB/s (${downloadTime}ms)`);
|
|
144
|
+
|
|
145
|
+
await client.delete('large-test.bin');
|
|
146
|
+
console.log(` Cleaned up large-test.bin`);
|
|
147
|
+
|
|
148
|
+
// Test 18: Try chmod (may not work on all servers)
|
|
149
|
+
console.log('\nโ
TEST 18: Change file permissions (chmod)');
|
|
150
|
+
try {
|
|
151
|
+
await client.chmod('renamed-file.txt', '644');
|
|
152
|
+
console.log(' Changed permissions to 644');
|
|
153
|
+
} catch (err) {
|
|
154
|
+
console.log(` Not supported or error: ${err.message}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Test 19: Execute SITE command
|
|
158
|
+
console.log('\nโ
TEST 19: Execute SITE command');
|
|
159
|
+
try {
|
|
160
|
+
const response = await client.site('HELP');
|
|
161
|
+
console.log(` SITE HELP response: ${response.message.substring(0, 50)}...`);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
console.log(` Not supported or error: ${err.message}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Test 20: Check connection state
|
|
167
|
+
console.log('\nโ
TEST 20: Get client state');
|
|
168
|
+
const state = client.getStats();
|
|
169
|
+
console.log(` Connected: ${state.connected}, Authenticated: ${state.authenticated}`);
|
|
170
|
+
console.log(` Commands executed: ${state.commandCount}`);
|
|
171
|
+
|
|
172
|
+
// Test 21: Delete single file
|
|
173
|
+
console.log('\nโ
TEST 21: Delete single file');
|
|
174
|
+
await client.delete('test-dir-1/buffer-test.bin');
|
|
175
|
+
console.log(' Deleted buffer-test.bin');
|
|
176
|
+
|
|
177
|
+
// Test 22: Remove empty directory
|
|
178
|
+
console.log('\nโ
TEST 22: Remove empty directory');
|
|
179
|
+
await client.removeDir('test-dir-1');
|
|
180
|
+
console.log(' Removed test-dir-1');
|
|
181
|
+
|
|
182
|
+
// Test 23: Remove directory recursively
|
|
183
|
+
console.log('\nโ
TEST 23: Remove directory recursively');
|
|
184
|
+
await client.removeDir('subdir', true);
|
|
185
|
+
console.log(' Recursively removed subdir and all contents');
|
|
186
|
+
|
|
187
|
+
// Test 24: Final directory listing
|
|
188
|
+
console.log('\nโ
TEST 24: Final directory listing');
|
|
189
|
+
const finalListing = await client.listDetailed('.');
|
|
190
|
+
console.log(` Items remaining: ${finalListing.length}`);
|
|
191
|
+
|
|
192
|
+
// Cleanup: Remove test directory
|
|
193
|
+
console.log('\n๐งน CLEANUP: Removing test directory');
|
|
194
|
+
await client.cd('..');
|
|
195
|
+
await client.removeDir(TEST_DIR, true);
|
|
196
|
+
console.log(` Removed ${TEST_DIR} and all contents`);
|
|
197
|
+
|
|
198
|
+
// Close connection
|
|
199
|
+
console.log('\nโ
Closing connection');
|
|
200
|
+
await client.close();
|
|
201
|
+
console.log(' Connection closed');
|
|
202
|
+
|
|
203
|
+
console.log('\n' + '='.repeat(60));
|
|
204
|
+
console.log('๐ ALL TESTS PASSED!');
|
|
205
|
+
console.log('='.repeat(60) + '\n');
|
|
206
|
+
|
|
207
|
+
} catch (err) {
|
|
208
|
+
console.error('\nโ TEST FAILED:', err.message);
|
|
209
|
+
console.error('Stack:', err.stack);
|
|
210
|
+
|
|
211
|
+
// Try to cleanup and close
|
|
212
|
+
try {
|
|
213
|
+
console.log('\n๐งน Attempting cleanup...');
|
|
214
|
+
await client.cd('/');
|
|
215
|
+
try {
|
|
216
|
+
await client.removeDir(TEST_DIR, true);
|
|
217
|
+
console.log(' Cleaned up test directory');
|
|
218
|
+
} catch (e) {
|
|
219
|
+
console.log(' Could not clean up:', e.message);
|
|
220
|
+
}
|
|
221
|
+
await client.close();
|
|
222
|
+
} catch (e) {
|
|
223
|
+
console.log(' Could not close connection:', e.message);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Run the tests
|
|
231
|
+
console.log('Starting comprehensive FTP client tests...');
|
|
232
|
+
runTests().catch(err => {
|
|
233
|
+
console.error('Fatal error:', err);
|
|
234
|
+
process.exit(1);
|
|
235
|
+
});
|
package/benchmark.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performance benchmark for FTP client
|
|
3
|
-
* Compare different performance presets
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const FTPClient = require('./index.js');
|
|
7
|
-
|
|
8
|
-
async function benchmark() {
|
|
9
|
-
const testData = 'x'.repeat(50000); // 50KB test data
|
|
10
|
-
const presets = ['DEFAULT', 'LOW_LATENCY', 'HIGH_THROUGHPUT', 'BALANCED'];
|
|
11
|
-
|
|
12
|
-
console.log('\n=== FTP Client Performance Benchmark ===\n');
|
|
13
|
-
console.log('Test data size:', testData.length, 'bytes\n');
|
|
14
|
-
|
|
15
|
-
for (const preset of presets) {
|
|
16
|
-
console.log(`Testing ${preset} preset...`);
|
|
17
|
-
|
|
18
|
-
const client = new FTPClient({
|
|
19
|
-
debug: false,
|
|
20
|
-
timeout: 60000,
|
|
21
|
-
performancePreset: preset
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
// Connect
|
|
26
|
-
const connectStart = Date.now();
|
|
27
|
-
await client.connect({
|
|
28
|
-
host: 'ftp.example.com',
|
|
29
|
-
port: 21,
|
|
30
|
-
user: 'username',
|
|
31
|
-
password: 'password'
|
|
32
|
-
});
|
|
33
|
-
const connectTime = Date.now() - connectStart;
|
|
34
|
-
|
|
35
|
-
// Upload
|
|
36
|
-
const uploadStart = Date.now();
|
|
37
|
-
await client.upload(testData, '/benchmark-test.txt', true);
|
|
38
|
-
const uploadTime = Date.now() - uploadStart;
|
|
39
|
-
|
|
40
|
-
// Download
|
|
41
|
-
const downloadStart = Date.now();
|
|
42
|
-
const data = await client.download('/benchmark-test.txt');
|
|
43
|
-
const downloadTime = Date.now() - downloadStart;
|
|
44
|
-
|
|
45
|
-
// Cleanup
|
|
46
|
-
await client.delete('/benchmark-test.txt');
|
|
47
|
-
await client.close();
|
|
48
|
-
|
|
49
|
-
console.log(` Connect: ${connectTime}ms`);
|
|
50
|
-
console.log(` Upload: ${uploadTime}ms`);
|
|
51
|
-
console.log(` Download: ${downloadTime}ms`);
|
|
52
|
-
console.log(` Total: ${connectTime + uploadTime + downloadTime}ms`);
|
|
53
|
-
console.log('');
|
|
54
|
-
|
|
55
|
-
} catch (err) {
|
|
56
|
-
console.error(` Error: ${err.message}\n`);
|
|
57
|
-
await client.close();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Wait between tests
|
|
61
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
console.log('=== Benchmark Complete ===\n');
|
|
65
|
-
console.log('Recommendation:');
|
|
66
|
-
console.log(' - Use LOW_LATENCY for small files (< 1MB)');
|
|
67
|
-
console.log(' - Use HIGH_THROUGHPUT for large files (> 10MB)');
|
|
68
|
-
console.log(' - Use BALANCED for mixed workloads\n');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Only run if called directly
|
|
72
|
-
if (require.main === module) {
|
|
73
|
-
console.log('\nโ ๏ธ Update the benchmark() function with your FTP credentials to test.\n');
|
|
74
|
-
console.log('Example:');
|
|
75
|
-
console.log(' await client.connect({');
|
|
76
|
-
console.log(' host: "ftp.example.com",');
|
|
77
|
-
console.log(' port: 21,');
|
|
78
|
-
console.log(' user: "username",');
|
|
79
|
-
console.log(' password: "password"');
|
|
80
|
-
console.log(' });\n');
|
|
81
|
-
|
|
82
|
-
// Uncomment to run benchmark:
|
|
83
|
-
// benchmark();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
module.exports = benchmark;
|