mirror of
https://github.com/zoriya/flood.git
synced 2025-12-06 07:16:18 +00:00
server: initial tests for torrents endpoints
This commit is contained in:
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -23,6 +23,8 @@ jobs:
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- run: sudo apt-get install -y rtorrent
|
||||
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npm run start -- --help
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"start:development:server": "NODE_ENV=development TS_NODE_PROJECT=server/tsconfig.json ts-node-dev --transpile-only server/bin/start.ts",
|
||||
"start:production": "UPDATED_SCRIPT=start npm run deprecated-warning && npm start",
|
||||
"start:watch": "UPDATED_SCRIPT=start:development:client npm run deprecated-warning && npm run start:development:client",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watchAll"
|
||||
"test": "jest --forceExit",
|
||||
"test:watch": "jest --watchAll --forceExit"
|
||||
},
|
||||
"dependencies": {
|
||||
"argon2-browser": "^1.15.1",
|
||||
|
||||
@@ -2,12 +2,44 @@ import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import {spawn} from 'child_process';
|
||||
|
||||
const temporaryRuntimeDirectory = path.resolve(os.tmpdir(), crypto.randomBytes(12).toString('hex'));
|
||||
|
||||
const rTorrentSession = path.join(temporaryRuntimeDirectory, '.session');
|
||||
const rTorrentSocket = path.join(temporaryRuntimeDirectory, 'rtorrent.sock');
|
||||
|
||||
fs.mkdirSync(rTorrentSession, {recursive: true});
|
||||
|
||||
const rTorrentProcess = spawn(
|
||||
'rtorrent',
|
||||
[
|
||||
'-n',
|
||||
'-d',
|
||||
temporaryRuntimeDirectory,
|
||||
'-s',
|
||||
rTorrentSession,
|
||||
'-o',
|
||||
'system.daemon.set=true',
|
||||
'-o',
|
||||
`network.scgi.open_local=${rTorrentSocket}`,
|
||||
],
|
||||
{
|
||||
stdio: 'ignore',
|
||||
killSignal: 'SIGKILL',
|
||||
},
|
||||
);
|
||||
|
||||
process.argv = ['node', 'flood'];
|
||||
process.argv.push('--rundir', temporaryRuntimeDirectory);
|
||||
process.argv.push('--noauth');
|
||||
process.argv.push('--rtsocket', '/home/download/rtorrent.sock');
|
||||
process.argv.push('--rtsocket', rTorrentSocket);
|
||||
|
||||
afterAll(() => fs.rmdirSync(temporaryRuntimeDirectory, {recursive: true}));
|
||||
afterAll((done) => {
|
||||
rTorrentProcess.on('close', () => {
|
||||
fs.rmdirSync(temporaryRuntimeDirectory, {recursive: true});
|
||||
done();
|
||||
});
|
||||
|
||||
rTorrentProcess.kill('SIGKILL');
|
||||
});
|
||||
|
||||
@@ -29,6 +29,14 @@ router.use('/feed-monitor', feedMonitorRoutes);
|
||||
|
||||
router.use('/torrents', torrentsRoutes);
|
||||
|
||||
/**
|
||||
* GET /api/activity-stream
|
||||
* @summary Subscribes to activity stream
|
||||
* @tags Flood
|
||||
* @security User
|
||||
* @return {EventSource<ServerEvent>} 200 - success response - text/event-stream
|
||||
* @return {Error} 500 - failure response - application/json
|
||||
*/
|
||||
router.get('/activity-stream', eventStream, clientActivityStream);
|
||||
|
||||
router.get<unknown, unknown, unknown, {path: string}>('/directory-list', (req, res) => {
|
||||
|
||||
92
server/routes/api/torrents.test.ts
Normal file
92
server/routes/api/torrents.test.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import fs from 'fs';
|
||||
import readline from 'readline';
|
||||
import stream from 'stream';
|
||||
import supertest from 'supertest';
|
||||
|
||||
import type {AddTorrentByURLOptions} from '../../../shared/types/api/torrents';
|
||||
import type {TorrentList, TorrentProperties} from '../../../shared/types/Torrent';
|
||||
import type {TorrentStatus} from '../../../shared/constants/torrentStatusMap';
|
||||
|
||||
import app from '../../app';
|
||||
import {getAuthToken} from './auth';
|
||||
|
||||
import {getTempPath} from '../../models/TemporaryStorage';
|
||||
|
||||
const request = supertest(app);
|
||||
|
||||
const authToken = `jwt=${getAuthToken('_config')}`;
|
||||
|
||||
const tempDirectory = getTempPath('rtorrent');
|
||||
|
||||
fs.mkdirSync(tempDirectory, {recursive: true});
|
||||
|
||||
jest.setTimeout(20000);
|
||||
|
||||
describe('POST /api/torrents/add-urls', () => {
|
||||
const addTorrentByURLOptions: AddTorrentByURLOptions = {
|
||||
urls: ['https://releases.ubuntu.com/20.04/ubuntu-20.04.1-live-server-amd64.iso.torrent'],
|
||||
destination: tempDirectory,
|
||||
tags: ['test'],
|
||||
isBasePath: false,
|
||||
start: false,
|
||||
};
|
||||
|
||||
const activityStream = new stream.PassThrough();
|
||||
const rl = readline.createInterface({input: activityStream});
|
||||
|
||||
const req = request.get('/api/activity-stream').send().set('Cookie', [authToken]);
|
||||
|
||||
const torrentAdded = new Promise((resolve) => {
|
||||
req.pipe(activityStream);
|
||||
rl.on('line', (input) => {
|
||||
if (input.includes('TORRENT_LIST_DIFF_CHANGE')) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Adds a torrent from URL', (done) => {
|
||||
request
|
||||
.post('/api/torrents/add-urls')
|
||||
.send(addTorrentByURLOptions)
|
||||
.set('Cookie', [authToken])
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.end((err, _res) => {
|
||||
if (err) done(err);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('GET /api/torrents', (done) => {
|
||||
torrentAdded.then(() => {
|
||||
request
|
||||
.get('/api/torrents')
|
||||
.send()
|
||||
.set('Cookie', [authToken])
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.end((err, res) => {
|
||||
if (err) done(err);
|
||||
|
||||
expect(res.body.torrents == null).toBe(false);
|
||||
const torrentList: TorrentList = res.body.torrents;
|
||||
|
||||
const [torrent]: Array<TorrentProperties> = Object.values(torrentList);
|
||||
|
||||
expect(torrent.baseDirectory).toBe(addTorrentByURLOptions.destination);
|
||||
expect(torrent.tags).toStrictEqual(addTorrentByURLOptions.tags);
|
||||
|
||||
const expectedStatuses: Array<TorrentStatus> = addTorrentByURLOptions.start
|
||||
? ['downloading']
|
||||
: ['stopped', 'inactive'];
|
||||
expect(torrent.status).toEqual(expect.arrayContaining(expectedStatuses));
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -26,6 +26,25 @@ import mediainfo from '../../util/mediainfo';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* GET /api/torrents
|
||||
* @summary Gets the list of torrents
|
||||
* @tags Torrents
|
||||
* @security User
|
||||
* @return {TorrentListSummary} 200 - success response - application/json
|
||||
* @return {Error} 500 - failure response - application/json
|
||||
*/
|
||||
router.get('/', (req, res) => {
|
||||
const callback = ajaxUtil.getResponseFn(res);
|
||||
|
||||
req.services?.torrentService
|
||||
.fetchTorrentList()
|
||||
.then(callback)
|
||||
.catch((err) => {
|
||||
callback(null, err);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/torrents/add-urls
|
||||
* @summary Adds torrents by URLs.
|
||||
|
||||
@@ -118,10 +118,12 @@ class TorrentService extends BaseService<TorrentServiceEvents> {
|
||||
clearTimeout(this.pollTimeout);
|
||||
}
|
||||
|
||||
return this.services?.clientGatewayService
|
||||
.fetchTorrentList()
|
||||
.then(this.handleFetchTorrentListSuccess)
|
||||
.catch(this.handleFetchTorrentListError);
|
||||
return (
|
||||
this.services?.clientGatewayService
|
||||
.fetchTorrentList()
|
||||
.then(this.handleFetchTorrentListSuccess)
|
||||
.catch(this.handleFetchTorrentListError) || Promise.reject()
|
||||
);
|
||||
}
|
||||
|
||||
getTorrent(hash: TorrentProperties['hash']) {
|
||||
|
||||
Reference in New Issue
Block a user