Files
2026-07-13 12:46:20 +08:00

159 lines
3.9 KiB
JavaScript

// ftp-transfer.spec.js
const { test, expect } = require('@playwright/test')
const { spawn } = require('child_process')
const path = require('path')
const fs = require('fs')
const { Transfer } = require('../../src/app/server/ftp-transfer')
const { Ftp } = require('../../src/app/server/session-ftp')
test.describe('FtpTransfer Class', () => {
let ftpServer
let ftp
test.beforeAll(async () => {
// Start the FTP test server
const serverPath = path.join(__dirname, '../e2e/common/ftp.js')
ftpServer = spawn('node', [serverPath])
await new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('FTP server start timeout'))
}, 5000)
ftpServer.stdout.on('data', (data) => {
if (data.toString().includes('FTP server is running at port 21')) {
clearTimeout(timeout)
resolve()
}
})
})
})
test.afterAll(async () => {
ftpServer.kill()
await new Promise((resolve) => ftpServer.on('close', resolve))
})
test.beforeEach(async () => {
const initOptions = {
host: 'localhost',
port: 21,
user: 'test',
password: 'test123'
}
ftp = new Ftp(initOptions)
await ftp.connect(initOptions)
})
test.afterEach(() => {
if (ftp) {
ftp.kill()
}
})
test('should handle file transfer events', async () => {
const localPath = path.join(__dirname, 'test-upload.txt')
const remotePath = '/test-upload.txt'
const testContent = 'x'.repeat(1024 * 1024) // 1MB file
let dataEventCalled = false
let endEventCalled = false
await fs.promises.writeFile(localPath, testContent)
const transfer = new Transfer({
remotePath,
localPath,
type: 'upload',
sftp: ftp.client,
sftpId: '1',
sessionId: '1',
id: '1',
options: {
ftp: true
},
ws: {
s: (event) => {
if (event.id.startsWith('transfer:data:')) {
dataEventCalled = true
}
if (event.id.startsWith('transfer:end:')) {
endEventCalled = true
}
},
close: () => {}
}
})
console.log('transfer', transfer)
await transfer.start()
await new Promise(resolve => setTimeout(resolve, 1000))
expect(dataEventCalled).toBe(true)
expect(endEventCalled).toBe(true)
await ftp.rm(remotePath)
await fs.promises.unlink(localPath)
})
test('should pause and resume transfer', async () => {
const transfer = new Transfer({
remotePath: '/test.txt',
localPath: 'test.txt',
type: 'upload',
sftp: ftp.client,
id: '1',
ws: {
s: () => {},
close: () => {}
}
})
transfer.pause()
expect(transfer.pausing).toBe(true)
transfer.resume()
expect(transfer.pausing).toBe(false)
})
test('should properly destroy transfer', async () => {
const transfer = new Transfer({
remotePath: '/test.txt',
localPath: 'test.txt',
type: 'upload',
sftp: ftp.client,
id: '1',
ws: {
s: () => {},
close: () => {}
}
})
transfer.destroy()
await new Promise(resolve => setTimeout(resolve, 300))
expect(transfer.onDestroy).toBe(true)
expect(transfer.src).toBe(null)
expect(transfer.dst).toBe(null)
expect(transfer.ftpClient).toBe(null)
})
test('should handle transfer errors', async () => {
let errorCalled = false
const transfer = new Transfer({
remotePath: '/nonexistent/path/test.txt',
localPath: 'test.txt',
type: 'upload',
sftp: ftp.client,
id: '1',
ws: {
s: (event) => {
if (event.id.startsWith('transfer:err:')) {
errorCalled = true
}
},
close: () => {}
}
})
await transfer.start()
await new Promise(resolve => setTimeout(resolve, 1000))
expect(errorCalled).toBe(true)
})
})