server: initial tests for torrents endpoints

This commit is contained in:
Jesse Chan
2020-10-13 02:11:30 +08:00
parent eb0aa56e38
commit 3ea6a93904
7 changed files with 164 additions and 9 deletions

View File

@@ -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

View File

@@ -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",

View File

@@ -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');
});

View File

@@ -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) => {

View 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();
});
});
});
});

View File

@@ -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.

View File

@@ -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']) {