aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/extra-utils/miscs
diff options
context:
space:
mode:
Diffstat (limited to 'shared/extra-utils/miscs')
-rw-r--r--shared/extra-utils/miscs/email-child-process.js27
-rw-r--r--shared/extra-utils/miscs/email.ts64
-rw-r--r--shared/extra-utils/miscs/miscs.ts101
-rw-r--r--shared/extra-utils/miscs/sql.ts80
-rw-r--r--shared/extra-utils/miscs/stubs.ts14
5 files changed, 286 insertions, 0 deletions
diff --git a/shared/extra-utils/miscs/email-child-process.js b/shared/extra-utils/miscs/email-child-process.js
new file mode 100644
index 000000000..40ae37d70
--- /dev/null
+++ b/shared/extra-utils/miscs/email-child-process.js
@@ -0,0 +1,27 @@
1const MailDev = require('maildev')
2
3// must run maildev as forked ChildProcess
4// failed instantiation stops main process with exit code 0
5process.on('message', (msg) => {
6 if (msg.start) {
7 const maildev = new MailDev({
8 ip: '127.0.0.1',
9 smtp: 1025,
10 disableWeb: true,
11 silent: true
12 })
13
14 maildev.on('new', email => {
15 process.send({ email })
16 })
17
18 maildev.listen(err => {
19 if (err) {
20 // cannot send as Error object
21 return process.send({ err: err.message })
22 }
23
24 return process.send({ err: null })
25 })
26 }
27})
diff --git a/shared/extra-utils/miscs/email.ts b/shared/extra-utils/miscs/email.ts
new file mode 100644
index 000000000..f9f1bd95b
--- /dev/null
+++ b/shared/extra-utils/miscs/email.ts
@@ -0,0 +1,64 @@
1import { fork, ChildProcess } from 'child_process'
2
3class MockSmtpServer {
4
5 private static instance: MockSmtpServer
6 private started = false
7 private emailChildProcess: ChildProcess
8 private emails: object[]
9
10 private constructor () {
11 this.emailChildProcess = fork(`${__dirname}/email-child-process`, [])
12
13 this.emailChildProcess.on('message', (msg) => {
14 if (msg.email) {
15 return this.emails.push(msg.email)
16 }
17 })
18
19 process.on('exit', () => this.kill())
20 }
21
22 collectEmails (emailsCollection: object[]) {
23 return new Promise((res, rej) => {
24 if (this.started) {
25 this.emails = emailsCollection
26 return res()
27 }
28
29 // ensure maildev isn't started until
30 // unexpected exit can be reported to test runner
31 this.emailChildProcess.send({ start: true })
32 this.emailChildProcess.on('exit', () => {
33 return rej(new Error('maildev exited unexpectedly, confirm port not in use'))
34 })
35 this.emailChildProcess.on('message', (msg) => {
36 if (msg.err) {
37 return rej(new Error(msg.err))
38 }
39 this.started = true
40 this.emails = emailsCollection
41 return res()
42 })
43 })
44 }
45
46 kill () {
47 if (!this.emailChildProcess) return
48
49 process.kill(this.emailChildProcess.pid)
50
51 this.emailChildProcess = null
52 MockSmtpServer.instance = null
53 }
54
55 static get Instance () {
56 return this.instance || (this.instance = new this())
57 }
58}
59
60// ---------------------------------------------------------------------------
61
62export {
63 MockSmtpServer
64}
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts
new file mode 100644
index 000000000..d1ffb7be4
--- /dev/null
+++ b/shared/extra-utils/miscs/miscs.ts
@@ -0,0 +1,101 @@
1/* tslint:disable:no-unused-expression */
2
3import * as chai from 'chai'
4import { isAbsolute, join } from 'path'
5import * as request from 'supertest'
6import * as WebTorrent from 'webtorrent'
7import { pathExists, readFile } from 'fs-extra'
8import * as ffmpeg from 'fluent-ffmpeg'
9
10const expect = chai.expect
11let webtorrent = new WebTorrent()
12
13function immutableAssign <T, U> (target: T, source: U) {
14 return Object.assign<{}, T, U>({}, target, source)
15}
16
17 // Default interval -> 5 minutes
18function dateIsValid (dateString: string, interval = 300000) {
19 const dateToCheck = new Date(dateString)
20 const now = new Date()
21
22 return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval
23}
24
25function wait (milliseconds: number) {
26 return new Promise(resolve => setTimeout(resolve, milliseconds))
27}
28
29function webtorrentAdd (torrent: string, refreshWebTorrent = false) {
30 if (refreshWebTorrent === true) webtorrent = new WebTorrent()
31
32 return new Promise<WebTorrent.Torrent>(res => webtorrent.add(torrent, res))
33}
34
35function root () {
36 // We are in /miscs
37 return join(__dirname, '..', '..', '..')
38}
39
40async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') {
41 const res = await request(url)
42 .get(imagePath)
43 .expect(200)
44
45 const body = res.body
46
47 const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension))
48 const minLength = body.length - ((20 * body.length) / 100)
49 const maxLength = body.length + ((20 * body.length) / 100)
50
51 expect(data.length).to.be.above(minLength)
52 expect(data.length).to.be.below(maxLength)
53}
54
55function buildAbsoluteFixturePath (path: string, customTravisPath = false) {
56 if (isAbsolute(path)) {
57 return path
58 }
59
60 if (customTravisPath && process.env.TRAVIS) return join(process.env.HOME, 'fixtures', path)
61
62 return join(root(), 'server', 'tests', 'fixtures', path)
63}
64
65async function generateHighBitrateVideo () {
66 const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true)
67
68 const exists = await pathExists(tempFixturePath)
69 if (!exists) {
70
71 // Generate a random, high bitrate video on the fly, so we don't have to include
72 // a large file in the repo. The video needs to have a certain minimum length so
73 // that FFmpeg properly applies bitrate limits.
74 // https://stackoverflow.com/a/15795112
75 return new Promise<string>(async (res, rej) => {
76 ffmpeg()
77 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
78 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
79 .outputOptions([ '-maxrate 10M', '-bufsize 10M' ])
80 .output(tempFixturePath)
81 .on('error', rej)
82 .on('end', () => res(tempFixturePath))
83 .run()
84 })
85 }
86
87 return tempFixturePath
88}
89
90// ---------------------------------------------------------------------------
91
92export {
93 dateIsValid,
94 wait,
95 webtorrentAdd,
96 immutableAssign,
97 testImage,
98 buildAbsoluteFixturePath,
99 root,
100 generateHighBitrateVideo
101}
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts
new file mode 100644
index 000000000..b281471ce
--- /dev/null
+++ b/shared/extra-utils/miscs/sql.ts
@@ -0,0 +1,80 @@
1import * as Sequelize from 'sequelize'
2
3let sequelizes: { [ id: number ]: Sequelize.Sequelize } = {}
4
5function getSequelize (serverNumber: number) {
6 if (sequelizes[serverNumber]) return sequelizes[serverNumber]
7
8 const dbname = 'peertube_test' + serverNumber
9 const username = 'peertube'
10 const password = 'peertube'
11 const host = 'localhost'
12 const port = 5432
13
14 const seq = new Sequelize(dbname, username, password, {
15 dialect: 'postgres',
16 host,
17 port,
18 operatorsAliases: false,
19 logging: false
20 })
21
22 sequelizes[serverNumber] = seq
23
24 return seq
25}
26
27function setActorField (serverNumber: number, to: string, field: string, value: string) {
28 const seq = getSequelize(serverNumber)
29
30 const options = { type: Sequelize.QueryTypes.UPDATE }
31
32 return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options)
33}
34
35function setVideoField (serverNumber: number, uuid: string, field: string, value: string) {
36 const seq = getSequelize(serverNumber)
37
38 const options = { type: Sequelize.QueryTypes.UPDATE }
39
40 return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
41}
42
43function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) {
44 const seq = getSequelize(serverNumber)
45
46 const options = { type: Sequelize.QueryTypes.UPDATE }
47
48 return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
49}
50
51async function countVideoViewsOf (serverNumber: number, uuid: string) {
52 const seq = getSequelize(serverNumber)
53
54 // tslint:disable
55 const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
56
57 const options = { type: Sequelize.QueryTypes.SELECT }
58 const [ { total } ] = await seq.query(query, options)
59
60 if (!total) return 0
61
62 return parseInt(total, 10)
63}
64
65async function closeAllSequelize (servers: any[]) {
66 for (let i = 1; i <= servers.length; i++) {
67 if (sequelizes[ i ]) {
68 await sequelizes[ i ].close()
69 delete sequelizes[ i ]
70 }
71 }
72}
73
74export {
75 setVideoField,
76 setPlaylistField,
77 setActorField,
78 countVideoViewsOf,
79 closeAllSequelize
80}
diff --git a/shared/extra-utils/miscs/stubs.ts b/shared/extra-utils/miscs/stubs.ts
new file mode 100644
index 000000000..d1eb0e3b2
--- /dev/null
+++ b/shared/extra-utils/miscs/stubs.ts
@@ -0,0 +1,14 @@
1function buildRequestStub (): any {
2 return { }
3}
4
5function buildResponseStub (): any {
6 return {
7 locals: {}
8 }
9}
10
11export {
12 buildResponseStub,
13 buildRequestStub
14}