From 6c5065a011b099618681a37bd77eaa7bd3db752e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 13 Jul 2021 09:43:59 +0200 Subject: Introduce server commands --- shared/extra-utils/miscs/checks.ts | 46 +++++++ shared/extra-utils/miscs/generate.ts | 61 +++++++++ shared/extra-utils/miscs/index.ts | 6 +- shared/extra-utils/miscs/miscs.ts | 170 ------------------------ shared/extra-utils/miscs/sql-command.ts | 2 +- shared/extra-utils/miscs/stubs.ts | 7 - shared/extra-utils/miscs/tests.ts | 62 +++++++++ shared/extra-utils/miscs/webtorrent.ts | 16 +++ shared/extra-utils/mock-servers/mock-email.ts | 4 +- shared/extra-utils/requests/check-api-params.ts | 11 +- shared/extra-utils/requests/requests.ts | 4 +- shared/extra-utils/server/directories.ts | 34 +++++ shared/extra-utils/server/index.ts | 2 + shared/extra-utils/server/jobs.ts | 2 +- shared/extra-utils/server/plugins-command.ts | 3 +- shared/extra-utils/server/servers-command.ts | 81 +++++++++++ shared/extra-utils/server/servers.ts | 108 ++------------- shared/extra-utils/shared/abstract-command.ts | 2 +- shared/extra-utils/videos/captions-command.ts | 4 +- shared/extra-utils/videos/live-command.ts | 7 +- shared/extra-utils/videos/live.ts | 4 +- shared/extra-utils/videos/playlists.ts | 2 +- shared/extra-utils/videos/videos.ts | 30 +---- 23 files changed, 345 insertions(+), 323 deletions(-) create mode 100644 shared/extra-utils/miscs/checks.ts create mode 100644 shared/extra-utils/miscs/generate.ts delete mode 100644 shared/extra-utils/miscs/miscs.ts delete mode 100644 shared/extra-utils/miscs/stubs.ts create mode 100644 shared/extra-utils/miscs/tests.ts create mode 100644 shared/extra-utils/miscs/webtorrent.ts create mode 100644 shared/extra-utils/server/directories.ts create mode 100644 shared/extra-utils/server/servers-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/checks.ts b/shared/extra-utils/miscs/checks.ts new file mode 100644 index 000000000..86b861cd2 --- /dev/null +++ b/shared/extra-utils/miscs/checks.ts @@ -0,0 +1,46 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ + +import { expect } from 'chai' +import { pathExists, readFile } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { HttpStatusCode } from '@shared/core-utils' +import { makeGetRequest } from '../requests' +import { ServerInfo } from '../server' + +// Default interval -> 5 minutes +function dateIsValid (dateString: string, interval = 300000) { + const dateToCheck = new Date(dateString) + const now = new Date() + + return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval +} + +async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { + const res = await makeGetRequest({ + url, + path: imagePath, + statusCodeExpected: HttpStatusCode.OK_200 + }) + + const body = res.body + + const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) + const minLength = body.length - ((30 * body.length) / 100) + const maxLength = body.length + ((30 * body.length) / 100) + + expect(data.length).to.be.above(minLength, 'the generated image is way smaller than the recorded fixture') + expect(data.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') +} + +async function testFileExistsOrNot (server: ServerInfo, directory: string, filePath: string, exist: boolean) { + const base = server.serversCommand.buildDirectory(directory) + + expect(await pathExists(join(base, filePath))).to.equal(exist) +} + +export { + dateIsValid, + testImage, + testFileExistsOrNot +} diff --git a/shared/extra-utils/miscs/generate.ts b/shared/extra-utils/miscs/generate.ts new file mode 100644 index 000000000..4e70ab853 --- /dev/null +++ b/shared/extra-utils/miscs/generate.ts @@ -0,0 +1,61 @@ +import { ensureDir, pathExists } from 'fs-extra' +import { dirname } from 'path' +import { buildAbsoluteFixturePath } from './tests' +import * as ffmpeg from 'fluent-ffmpeg' + +async function generateHighBitrateVideo () { + const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) + + await ensureDir(dirname(tempFixturePath)) + + const exists = await pathExists(tempFixturePath) + if (!exists) { + console.log('Generating high bitrate video.') + + // Generate a random, high bitrate video on the fly, so we don't have to include + // a large file in the repo. The video needs to have a certain minimum length so + // that FFmpeg properly applies bitrate limits. + // https://stackoverflow.com/a/15795112 + return new Promise((res, rej) => { + ffmpeg() + .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) + .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) + .outputOptions([ '-maxrate 10M', '-bufsize 10M' ]) + .output(tempFixturePath) + .on('error', rej) + .on('end', () => res(tempFixturePath)) + .run() + }) + } + + return tempFixturePath +} + +async function generateVideoWithFramerate (fps = 60) { + const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) + + await ensureDir(dirname(tempFixturePath)) + + const exists = await pathExists(tempFixturePath) + if (!exists) { + console.log('Generating video with framerate %d.', fps) + + return new Promise((res, rej) => { + ffmpeg() + .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) + .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) + .outputOptions([ `-r ${fps}` ]) + .output(tempFixturePath) + .on('error', rej) + .on('end', () => res(tempFixturePath)) + .run() + }) + } + + return tempFixturePath +} + +export { + generateHighBitrateVideo, + generateVideoWithFramerate +} diff --git a/shared/extra-utils/miscs/index.ts b/shared/extra-utils/miscs/index.ts index 7e236c329..4474661de 100644 --- a/shared/extra-utils/miscs/index.ts +++ b/shared/extra-utils/miscs/index.ts @@ -1,3 +1,5 @@ -export * from './miscs' +export * from './checks' +export * from './generate' export * from './sql-command' -export * from './stubs' +export * from './tests' +export * from './webtorrent' diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts deleted file mode 100644 index 462b914d4..000000000 --- a/shared/extra-utils/miscs/miscs.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import * as chai from 'chai' -import * as ffmpeg from 'fluent-ffmpeg' -import { ensureDir, pathExists, readFile, stat } from 'fs-extra' -import { basename, dirname, isAbsolute, join, resolve } from 'path' -import * as request from 'supertest' -import * as WebTorrent from 'webtorrent' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -const expect = chai.expect -let webtorrent: WebTorrent.Instance - -function immutableAssign (target: T, source: U) { - return Object.assign<{}, T, U>({}, target, source) -} - -// Default interval -> 5 minutes -function dateIsValid (dateString: string, interval = 300000) { - const dateToCheck = new Date(dateString) - const now = new Date() - - return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval -} - -function wait (milliseconds: number) { - return new Promise(resolve => setTimeout(resolve, milliseconds)) -} - -function webtorrentAdd (torrent: string, refreshWebTorrent = false) { - const WebTorrent = require('webtorrent') - - if (!webtorrent) webtorrent = new WebTorrent() - if (refreshWebTorrent === true) webtorrent = new WebTorrent() - - return new Promise(res => webtorrent.add(torrent, res)) -} - -function root () { - // We are in /miscs - let root = join(__dirname, '..', '..', '..') - - if (basename(root) === 'dist') root = resolve(root, '..') - - return root -} - -function buildServerDirectory (server: { internalServerNumber: number }, directory: string) { - return join(root(), 'test' + server.internalServerNumber, directory) -} - -async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { - const res = await request(url) - .get(imagePath) - .expect(HttpStatusCode.OK_200) - - const body = res.body - - const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) - const minLength = body.length - ((30 * body.length) / 100) - const maxLength = body.length + ((30 * body.length) / 100) - - expect(data.length).to.be.above(minLength, 'the generated image is way smaller than the recorded fixture') - expect(data.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') -} - -async function testFileExistsOrNot (server: { internalServerNumber: number }, directory: string, filePath: string, exist: boolean) { - const base = buildServerDirectory(server, directory) - - expect(await pathExists(join(base, filePath))).to.equal(exist) -} - -function isGithubCI () { - return !!process.env.GITHUB_WORKSPACE -} - -function buildAbsoluteFixturePath (path: string, customCIPath = false) { - if (isAbsolute(path)) return path - - if (customCIPath && process.env.GITHUB_WORKSPACE) { - return join(process.env.GITHUB_WORKSPACE, 'fixtures', path) - } - - return join(root(), 'server', 'tests', 'fixtures', path) -} - -function areHttpImportTestsDisabled () { - const disabled = process.env.DISABLE_HTTP_IMPORT_TESTS === 'true' - - if (disabled) console.log('Import tests are disabled') - - return disabled -} - -async function generateHighBitrateVideo () { - const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) - - await ensureDir(dirname(tempFixturePath)) - - const exists = await pathExists(tempFixturePath) - if (!exists) { - console.log('Generating high bitrate video.') - - // Generate a random, high bitrate video on the fly, so we don't have to include - // a large file in the repo. The video needs to have a certain minimum length so - // that FFmpeg properly applies bitrate limits. - // https://stackoverflow.com/a/15795112 - return new Promise((res, rej) => { - ffmpeg() - .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) - .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) - .outputOptions([ '-maxrate 10M', '-bufsize 10M' ]) - .output(tempFixturePath) - .on('error', rej) - .on('end', () => res(tempFixturePath)) - .run() - }) - } - - return tempFixturePath -} - -async function generateVideoWithFramerate (fps = 60) { - const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) - - await ensureDir(dirname(tempFixturePath)) - - const exists = await pathExists(tempFixturePath) - if (!exists) { - console.log('Generating video with framerate %d.', fps) - - return new Promise((res, rej) => { - ffmpeg() - .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) - .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) - .outputOptions([ `-r ${fps}` ]) - .output(tempFixturePath) - .on('error', rej) - .on('end', () => res(tempFixturePath)) - .run() - }) - } - - return tempFixturePath -} - -async function getFileSize (path: string) { - const stats = await stat(path) - - return stats.size -} - -// --------------------------------------------------------------------------- - -export { - dateIsValid, - wait, - areHttpImportTestsDisabled, - buildServerDirectory, - webtorrentAdd, - getFileSize, - immutableAssign, - testImage, - isGithubCI, - buildAbsoluteFixturePath, - testFileExistsOrNot, - root, - generateHighBitrateVideo, - generateVideoWithFramerate -} diff --git a/shared/extra-utils/miscs/sql-command.ts b/shared/extra-utils/miscs/sql-command.ts index 2a3e9e607..80c8cd271 100644 --- a/shared/extra-utils/miscs/sql-command.ts +++ b/shared/extra-utils/miscs/sql-command.ts @@ -1,5 +1,5 @@ import { QueryTypes, Sequelize } from 'sequelize' -import { AbstractCommand } from '../shared' +import { AbstractCommand } from '../shared/abstract-command' export class SQLCommand extends AbstractCommand { private sequelize: Sequelize diff --git a/shared/extra-utils/miscs/stubs.ts b/shared/extra-utils/miscs/stubs.ts deleted file mode 100644 index 940e4bf29..000000000 --- a/shared/extra-utils/miscs/stubs.ts +++ /dev/null @@ -1,7 +0,0 @@ -function buildRequestStub (): any { - return { } -} - -export { - buildRequestStub -} diff --git a/shared/extra-utils/miscs/tests.ts b/shared/extra-utils/miscs/tests.ts new file mode 100644 index 000000000..8f7a2f92b --- /dev/null +++ b/shared/extra-utils/miscs/tests.ts @@ -0,0 +1,62 @@ +import { stat } from 'fs-extra' +import { basename, isAbsolute, join, resolve } from 'path' + +function parallelTests () { + return process.env.MOCHA_PARALLEL === 'true' +} + +function isGithubCI () { + return !!process.env.GITHUB_WORKSPACE +} + +function areHttpImportTestsDisabled () { + const disabled = process.env.DISABLE_HTTP_IMPORT_TESTS === 'true' + + if (disabled) console.log('Import tests are disabled') + + return disabled +} + +function buildAbsoluteFixturePath (path: string, customCIPath = false) { + if (isAbsolute(path)) return path + + if (customCIPath && process.env.GITHUB_WORKSPACE) { + return join(process.env.GITHUB_WORKSPACE, 'fixtures', path) + } + + return join(root(), 'server', 'tests', 'fixtures', path) +} + +function root () { + // We are in /miscs + let root = join(__dirname, '..', '..', '..') + + if (basename(root) === 'dist') root = resolve(root, '..') + + return root +} + +function wait (milliseconds: number) { + return new Promise(resolve => setTimeout(resolve, milliseconds)) +} + +async function getFileSize (path: string) { + const stats = await stat(path) + + return stats.size +} + +function buildRequestStub (): any { + return { } +} + +export { + parallelTests, + isGithubCI, + areHttpImportTestsDisabled, + buildAbsoluteFixturePath, + getFileSize, + buildRequestStub, + wait, + root +} diff --git a/shared/extra-utils/miscs/webtorrent.ts b/shared/extra-utils/miscs/webtorrent.ts new file mode 100644 index 000000000..82548946d --- /dev/null +++ b/shared/extra-utils/miscs/webtorrent.ts @@ -0,0 +1,16 @@ +import * as WebTorrent from 'webtorrent' + +let webtorrent: WebTorrent.Instance + +function webtorrentAdd (torrent: string, refreshWebTorrent = false) { + const WebTorrent = require('webtorrent') + + if (!webtorrent) webtorrent = new WebTorrent() + if (refreshWebTorrent === true) webtorrent = new WebTorrent() + + return new Promise(res => webtorrent.add(torrent, res)) +} + +export { + webtorrentAdd +} diff --git a/shared/extra-utils/mock-servers/mock-email.ts b/shared/extra-utils/mock-servers/mock-email.ts index 9fc9a5ad0..ffd62e325 100644 --- a/shared/extra-utils/mock-servers/mock-email.ts +++ b/shared/extra-utils/mock-servers/mock-email.ts @@ -1,6 +1,6 @@ import { ChildProcess } from 'child_process' -import { randomInt } from '../../core-utils/miscs/miscs' -import { parallelTests } from '../server/servers' +import { randomInt } from '@shared/core-utils' +import { parallelTests } from '../miscs' const MailDev = require('maildev') diff --git a/shared/extra-utils/requests/check-api-params.ts b/shared/extra-utils/requests/check-api-params.ts index 7f5ff775c..7df63b004 100644 --- a/shared/extra-utils/requests/check-api-params.ts +++ b/shared/extra-utils/requests/check-api-params.ts @@ -1,13 +1,12 @@ +import { HttpStatusCode } from '@shared/core-utils' import { makeGetRequest } from './requests' -import { immutableAssign } from '../miscs/miscs' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' function checkBadStartPagination (url: string, path: string, token?: string, query = {}) { return makeGetRequest({ url, path, token, - query: immutableAssign(query, { start: 'hello' }), + query: { ...query, start: 'hello' }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) } @@ -17,7 +16,7 @@ async function checkBadCountPagination (url: string, path: string, token?: strin url, path, token, - query: immutableAssign(query, { count: 'hello' }), + query: { ...query, count: 'hello' }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) @@ -25,7 +24,7 @@ async function checkBadCountPagination (url: string, path: string, token?: strin url, path, token, - query: immutableAssign(query, { count: 2000 }), + query: { ...query, count: 2000 }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) } @@ -35,7 +34,7 @@ function checkBadSortPagination (url: string, path: string, token?: string, quer url, path, token, - query: immutableAssign(query, { sort: 'hello' }), + query: { ...query, sort: 'hello' }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) } diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 3fbaa31d6..f9d112aca 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -4,8 +4,8 @@ import { isAbsolute, join } from 'path' import { decode } from 'querystring' import * as request from 'supertest' import { URL } from 'url' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { buildAbsoluteFixturePath, root } from '../miscs/miscs' +import { HttpStatusCode } from '@shared/core-utils' +import { buildAbsoluteFixturePath, root } from '../miscs/tests' function get4KFileUrl () { return 'https://download.cpy.re/peertube/4k_file.txt' diff --git a/shared/extra-utils/server/directories.ts b/shared/extra-utils/server/directories.ts new file mode 100644 index 000000000..3cd38a561 --- /dev/null +++ b/shared/extra-utils/server/directories.ts @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { pathExists, readdir } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { ServerInfo } from './servers' + +async function checkTmpIsEmpty (server: ServerInfo) { + await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) + + if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { + await checkDirectoryIsEmpty(server, 'tmp/hls') + } +} + +async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exceptions: string[] = []) { + const testDirectory = 'test' + server.internalServerNumber + + const directoryPath = join(root(), testDirectory, directory) + + const directoryExists = await pathExists(directoryPath) + expect(directoryExists).to.be.true + + const files = await readdir(directoryPath) + const filtered = files.filter(f => exceptions.includes(f) === false) + + expect(filtered).to.have.lengthOf(0) +} + +export { + checkTmpIsEmpty, + checkDirectoryIsEmpty +} diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index 03c3b0123..669b004cd 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -1,6 +1,7 @@ export * from './config-command' export * from './contact-form-command' export * from './debug-command' +export * from './directories' export * from './follows-command' export * from './follows' export * from './jobs' @@ -8,5 +9,6 @@ export * from './jobs-command' export * from './plugins-command' export * from './plugins' export * from './redundancy-command' +export * from './servers-command' export * from './servers' export * from './stats-command' diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index b4b3d52e7..36ef882b3 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts @@ -1,6 +1,6 @@ import { JobState } from '../../models' -import { wait } from '../miscs/miscs' +import { wait } from '../miscs' import { ServerInfo } from './servers' async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts index ff49d58c4..5bed51d1a 100644 --- a/shared/extra-utils/server/plugins-command.ts +++ b/shared/extra-utils/server/plugins-command.ts @@ -15,7 +15,6 @@ import { RegisteredServerSettings, ResultList } from '@shared/models' -import { buildServerDirectory } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class PluginsCommand extends AbstractCommand { @@ -252,6 +251,6 @@ export class PluginsCommand extends AbstractCommand { } private getPackageJSONPath (npmName: string) { - return buildServerDirectory(this.server, join('plugins', 'node_modules', npmName, 'package.json')) + return this.server.serversCommand.buildDirectory(join('plugins', 'node_modules', npmName, 'package.json')) } } diff --git a/shared/extra-utils/server/servers-command.ts b/shared/extra-utils/server/servers-command.ts new file mode 100644 index 000000000..9ef68fede --- /dev/null +++ b/shared/extra-utils/server/servers-command.ts @@ -0,0 +1,81 @@ +import { exec } from 'child_process' +import { copy, ensureDir, readFile, remove } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { HttpStatusCode } from '@shared/core-utils' +import { getFileSize } from '@uploadx/core' +import { isGithubCI, wait } from '../miscs' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ServersCommand extends AbstractCommand { + + static flushTests (internalServerNumber: number) { + return new Promise((res, rej) => { + const suffix = ` -- ${internalServerNumber}` + + return exec('npm run clean:server:test' + suffix, (err, _stdout, stderr) => { + if (err || stderr) return rej(err || new Error(stderr)) + + return res() + }) + }) + } + + ping (options: OverrideCommandOptions = {}) { + return this.getRequestBody({ + ...options, + + path: '/api/v1/ping', + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + async cleanupTests () { + const p: Promise[] = [] + + if (isGithubCI()) { + await ensureDir('artifacts') + + const origin = this.server.serversCommand.buildDirectory('logs/peertube.log') + const destname = `peertube-${this.server.internalServerNumber}.log` + console.log('Saving logs %s.', destname) + + await copy(origin, join('artifacts', destname)) + } + + if (this.server.parallel) { + p.push(ServersCommand.flushTests(this.server.internalServerNumber)) + } + + if (this.server.customConfigFile) { + p.push(remove(this.server.customConfigFile)) + } + + return p + } + + async waitUntilLog (str: string, count = 1, strictCount = true) { + const logfile = this.server.serversCommand.buildDirectory('logs/peertube.log') + + while (true) { + const buf = await readFile(logfile) + + const matches = buf.toString().match(new RegExp(str, 'g')) + if (matches && matches.length === count) return + if (matches && strictCount === false && matches.length >= count) return + + await wait(1000) + } + } + + buildDirectory (directory: string) { + return join(root(), 'test' + this.server.internalServerNumber, directory) + } + + async getServerFileSize (subPath: string) { + const path = this.server.serversCommand.buildDirectory(subPath) + + return getFileSize(path) + } +} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index e0e49d2c4..f5dc0326f 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ -import { expect } from 'chai' -import { ChildProcess, exec, fork } from 'child_process' -import { copy, ensureDir, pathExists, readdir, readFile, remove } from 'fs-extra' +import { ChildProcess, fork } from 'child_process' +import { copy, ensureDir } from 'fs-extra' import { join } from 'path' +import { root } from '@server/helpers/core-utils' import { randomInt } from '../../core-utils/miscs/miscs' import { VideoChannel } from '../../models/videos' import { BulkCommand } from '../bulk' @@ -11,11 +11,9 @@ import { CLICommand } from '../cli' import { CustomPagesCommand } from '../custom-pages' import { FeedCommand } from '../feeds' import { LogsCommand } from '../logs' -import { SQLCommand } from '../miscs' -import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' +import { isGithubCI, parallelTests, SQLCommand } from '../miscs' import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' -import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, NotificationsCommand, SubscriptionsCommand } from '../users' @@ -39,6 +37,7 @@ import { FollowsCommand } from './follows-command' import { JobsCommand } from './jobs-command' import { PluginsCommand } from './plugins-command' import { RedundancyCommand } from './redundancy-command' +import { ServersCommand } from './servers-command' import { StatsCommand } from './stats-command' interface ServerInfo { @@ -126,10 +125,7 @@ interface ServerInfo { commentsCommand?: CommentsCommand sqlCommand?: SQLCommand notificationsCommand?: NotificationsCommand -} - -function parallelTests () { - return process.env.MOCHA_PARALLEL === 'true' + serversCommand?: ServersCommand } function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { @@ -151,18 +147,6 @@ function flushAndRunMultipleServers (totalServers: number, configOverride?: Obje }) } -function flushTests (serverNumber?: number) { - return new Promise((res, rej) => { - const suffix = serverNumber ? ` -- ${serverNumber}` : '' - - return exec('npm run clean:server:test' + suffix, (err, _stdout, stderr) => { - if (err || stderr) return rej(err || new Error(stderr)) - - return res() - }) - }) -} - function randomServer () { const low = 10 const high = 10000 @@ -189,7 +173,7 @@ async function flushAndRunServer (serverNumber: number, configOverride?: Object, const rtmpPort = parallel ? randomRTMP() : 1936 const port = 9000 + internalServerNumber - await flushTests(internalServerNumber) + await ServersCommand.flushTests(internalServerNumber) const server: ServerInfo = { app: null, @@ -372,6 +356,7 @@ function assignCommands (server: ServerInfo) { server.commentsCommand = new CommentsCommand(server) server.sqlCommand = new SQLCommand(server) server.notificationsCommand = new NotificationsCommand(server) + server.serversCommand = new ServersCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { @@ -381,28 +366,6 @@ async function reRunServer (server: ServerInfo, configOverride?: any) { return server } -async function checkTmpIsEmpty (server: ServerInfo) { - await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) - - if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { - await checkDirectoryIsEmpty(server, 'tmp/hls') - } -} - -async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exceptions: string[] = []) { - const testDirectory = 'test' + server.internalServerNumber - - const directoryPath = join(root(), testDirectory, directory) - - const directoryExists = await pathExists(directoryPath) - expect(directoryExists).to.be.true - - const files = await readdir(directoryPath) - const filtered = files.filter(f => exceptions.includes(f) === false) - - expect(filtered).to.have.lengthOf(0) -} - async function killallServers (servers: ServerInfo[]) { for (const server of servers) { if (!server.app) continue @@ -422,71 +385,22 @@ async function cleanupTests (servers: ServerInfo[]) { await ensureDir('artifacts') } - const p: Promise[] = [] + let p: Promise[] = [] for (const server of servers) { - if (isGithubCI()) { - const origin = await buildServerDirectory(server, 'logs/peertube.log') - const destname = `peertube-${server.internalServerNumber}.log` - console.log('Saving logs %s.', destname) - - await copy(origin, join('artifacts', destname)) - } - - if (server.parallel) { - p.push(flushTests(server.internalServerNumber)) - } - - if (server.customConfigFile) { - p.push(remove(server.customConfigFile)) - } + p = p.concat(server.serversCommand.cleanupTests()) } return Promise.all(p) } -async function waitUntilLog (server: ServerInfo, str: string, count = 1, strictCount = true) { - const logfile = buildServerDirectory(server, 'logs/peertube.log') - - while (true) { - const buf = await readFile(logfile) - - const matches = buf.toString().match(new RegExp(str, 'g')) - if (matches && matches.length === count) return - if (matches && strictCount === false && matches.length >= count) return - - await wait(1000) - } -} - -async function getServerFileSize (server: ServerInfo, subPath: string) { - const path = buildServerDirectory(server, subPath) - - return getFileSize(path) -} - -function makePingRequest (server: ServerInfo) { - return makeGetRequest({ - url: server.url, - path: '/api/v1/ping', - statusCodeExpected: 200 - }) -} - // --------------------------------------------------------------------------- export { - checkDirectoryIsEmpty, - checkTmpIsEmpty, - getServerFileSize, ServerInfo, - parallelTests, cleanupTests, flushAndRunMultipleServers, - flushTests, - makePingRequest, flushAndRunServer, killallServers, reRunServer, - assignCommands, - waitUntilLog + assignCommands } diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index fd2deb57e..4e61554a2 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,6 +1,6 @@ import { isAbsolute, join } from 'path' import { HttpStatusCode } from '@shared/core-utils' -import { root } from '../miscs/miscs' +import { root } from '../miscs/tests' import { makeDeleteRequest, makeGetRequest, diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts index 908b6dae6..ac3bde7a9 100644 --- a/shared/extra-utils/videos/captions-command.ts +++ b/shared/extra-utils/videos/captions-command.ts @@ -1,6 +1,6 @@ +import { HttpStatusCode } from '@shared/core-utils' import { ResultList, VideoCaption } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { buildAbsoluteFixturePath } from '../miscs/miscs' +import { buildAbsoluteFixturePath } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class CaptionsCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index 4f03c9127..a494e60fa 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -5,9 +5,8 @@ import { omit } from 'lodash' import { join } from 'path' import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { buildServerDirectory, wait } from '../miscs/miscs' +import { wait } from '../miscs' import { unwrapBody } from '../requests' -import { waitUntilLog } from '../server/servers' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { sendRTMPStream, testFfmpegStreamError } from './live' import { getVideoWithToken } from './videos' @@ -116,7 +115,7 @@ export class LiveCommand extends AbstractCommand { const { resolution, segment, videoUUID } = options const segmentName = `${resolution}-00000${segment}.ts` - return waitUntilLog(this.server, `${videoUUID}/${segmentName}`, 2, false) + return this.server.serversCommand.waitUntilLog(`${videoUUID}/${segmentName}`, 2, false) } async waitUntilSaved (options: OverrideCommandOptions & { @@ -135,7 +134,7 @@ export class LiveCommand extends AbstractCommand { async countPlaylists (options: OverrideCommandOptions & { videoUUID: string }) { - const basePath = buildServerDirectory(this.server, 'streaming-playlists') + const basePath = this.server.serversCommand.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', options.videoUUID) const files = await readdir(hlsPath) diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts index 92cb9104c..0efcc2883 100644 --- a/shared/extra-utils/videos/live.ts +++ b/shared/extra-utils/videos/live.ts @@ -4,7 +4,7 @@ import { expect } from 'chai' import * as ffmpeg from 'fluent-ffmpeg' import { pathExists, readdir } from 'fs-extra' import { join } from 'path' -import { buildAbsoluteFixturePath, buildServerDirectory, wait } from '../miscs/miscs' +import { buildAbsoluteFixturePath, wait } from '../miscs' import { ServerInfo } from '../server/servers' function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = 'video_short.mp4') { @@ -77,7 +77,7 @@ async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoI } async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) { - const basePath = buildServerDirectory(server, 'streaming-playlists') + const basePath = server.serversCommand.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', videoUUID) if (resolutions.length === 0) { diff --git a/shared/extra-utils/videos/playlists.ts b/shared/extra-utils/videos/playlists.ts index 023333c87..3dde52bb9 100644 --- a/shared/extra-utils/videos/playlists.ts +++ b/shared/extra-utils/videos/playlists.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { readdir } from 'fs-extra' import { join } from 'path' -import { root } from '../' +import { root } from '../miscs' async function checkPlaylistFilesWereRemoved ( playlistUUID: string, diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 920c93072..5dd71ce8b 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -13,15 +13,7 @@ import { HttpStatusCode } from '@shared/core-utils' import { BooleanBothQuery, VideosCommonQuery } from '@shared/models' import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants' import { VideoDetails, VideoPrivacy } from '../../models/videos' -import { - buildAbsoluteFixturePath, - buildServerDirectory, - dateIsValid, - immutableAssign, - testImage, - wait, - webtorrentAdd -} from '../miscs/miscs' +import { buildAbsoluteFixturePath, dateIsValid, testImage, wait, webtorrentAdd } from '../miscs' import { makeGetRequest, makePutBodyRequest, makeRawRequest, makeUploadRequest } from '../requests/requests' import { waitJobs } from '../server/jobs' import { ServerInfo } from '../server/servers' @@ -165,7 +157,7 @@ function getVideosListWithToken (url: string, token: string, query: { nsfw?: Boo return request(url) .get(path) .set('Authorization', 'Bearer ' + token) - .query(immutableAssign(query, { sort: 'name' })) + .query({ sort: 'name', ...query }) .set('Accept', 'application/json') .expect(HttpStatusCode.OK_200) .expect('Content-Type', /json/) @@ -228,11 +220,7 @@ function getAccountVideos ( return makeGetRequest({ url, path, - query: immutableAssign(query, { - start, - count, - sort - }), + query: { ...query, start, count, sort }, token: accessToken, statusCodeExpected: HttpStatusCode.OK_200 }) @@ -252,11 +240,7 @@ function getVideoChannelVideos ( return makeGetRequest({ url, path, - query: immutableAssign(query, { - start, - count, - sort - }), + query: { ...query, start, count, sort }, token: accessToken, statusCodeExpected: HttpStatusCode.OK_200 }) @@ -320,7 +304,7 @@ async function removeAllVideos (server: ServerInfo) { async function checkVideoFilesWereRemoved ( videoUUID: string, - serverNumber: number, + server: ServerInfo, directories = [ 'redundancy', 'videos', @@ -333,7 +317,7 @@ async function checkVideoFilesWereRemoved ( ] ) { for (const directory of directories) { - const directoryPath = buildServerDirectory({ internalServerNumber: serverNumber }, directory) + const directoryPath = server.serversCommand.buildDirectory(directory) const directoryExists = await pathExists(directoryPath) if (directoryExists === false) continue @@ -607,7 +591,7 @@ function rateVideo (url: string, accessToken: string, id: number | string, ratin function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) { return new Promise((res, rej) => { const torrentName = videoUUID + '-' + resolution + '.torrent' - const torrentPath = buildServerDirectory(server, join('torrents', torrentName)) + const torrentPath = server.serversCommand.buildDirectory(join('torrents', torrentName)) readFile(torrentPath, (err, data) => { if (err) return rej(err) -- cgit v1.2.3