]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - shared/extra-utils/miscs/miscs.ts
Add live transcoding bit rate tests
[github/Chocobozzz/PeerTube.git] / shared / extra-utils / miscs / miscs.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
9ee83eb9 2
7b0956ec 3import * as chai from 'chai'
ca5c612b
C
4import * as ffmpeg from 'fluent-ffmpeg'
5import { ensureDir, pathExists, readFile, stat } from 'fs-extra'
2284f202 6import { basename, dirname, isAbsolute, join, resolve } from 'path'
9ee83eb9 7import * as request from 'supertest'
0e1dc3e7 8import * as WebTorrent from 'webtorrent'
0e1dc3e7 9
7b0956ec 10const expect = chai.expect
8d2be0ed 11let webtorrent: WebTorrent.Instance
0e1dc3e7 12
a1587156 13function immutableAssign<T, U> (target: T, source: U) {
26d21b78
C
14 return Object.assign<{}, T, U>({}, target, source)
15}
16
a1587156 17// Default interval -> 5 minutes
b1f5b93e 18function dateIsValid (dateString: string, interval = 300000) {
0e1dc3e7
C
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) {
8d2be0ed
C
30 const WebTorrent = require('webtorrent')
31
32 if (!webtorrent) webtorrent = new WebTorrent()
0e1dc3e7
C
33 if (refreshWebTorrent === true) webtorrent = new WebTorrent()
34
35 return new Promise<WebTorrent.Torrent>(res => webtorrent.add(torrent, res))
36}
37
f05a1c30 38function root () {
94565d52 39 // We are in /miscs
1a12f66d
C
40 let root = join(__dirname, '..', '..', '..')
41
42 if (basename(root) === 'dist') root = resolve(root, '..')
43
44 return root
f05a1c30
C
45}
46
ca5c612b
C
47function buildServerDirectory (server: { internalServerNumber: number }, directory: string) {
48 return join(root(), 'test' + server.internalServerNumber, directory)
e2600d8b
C
49}
50
9ee83eb9 51async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') {
288178bf
C
52 const res = await request(url)
53 .get(imagePath)
54 .expect(200)
55
56 const body = res.body
57
2a8c5d0a 58 const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension))
e6dfa586
RK
59 const minLength = body.length - ((30 * body.length) / 100)
60 const maxLength = body.length + ((30 * body.length) / 100)
288178bf 61
e6dfa586
RK
62 expect(data.length).to.be.above(minLength, "the generated image is way smaller than the recorded fixture")
63 expect(data.length).to.be.below(maxLength, "the generated image is way larger than the recorded fixture")
9ee83eb9
C
64}
65
2284f202 66function buildAbsoluteFixturePath (path: string, customCIPath = false) {
b488ba1e 67 if (isAbsolute(path)) return path
ac81d1a0 68
07491f4b
C
69 if (customCIPath && process.env.GITHUB_WORKSPACE) {
70 return join(process.env.GITHUB_WORKSPACE, 'fixtures', path)
c928e136 71 }
c1c86c15 72
2a8c5d0a 73 return join(root(), 'server', 'tests', 'fixtures', path)
ac81d1a0
C
74}
75
b488ba1e
C
76function areHttpImportTestsDisabled () {
77 const disabled = process.env.DISABLE_HTTP_IMPORT_TESTS === 'true'
78
79 if (disabled) console.log('Import tests are disabled')
80
81 return disabled
82}
83
74cd011b
C
84async function generateHighBitrateVideo () {
85 const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true)
86
2284f202
C
87 await ensureDir(dirname(tempFixturePath))
88
74cd011b
C
89 const exists = await pathExists(tempFixturePath)
90 if (!exists) {
91
92 // Generate a random, high bitrate video on the fly, so we don't have to include
93 // a large file in the repo. The video needs to have a certain minimum length so
94 // that FFmpeg properly applies bitrate limits.
95 // https://stackoverflow.com/a/15795112
a1587156 96 return new Promise<string>((res, rej) => {
74cd011b
C
97 ffmpeg()
98 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
99 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
100 .outputOptions([ '-maxrate 10M', '-bufsize 10M' ])
101 .output(tempFixturePath)
102 .on('error', rej)
103 .on('end', () => res(tempFixturePath))
104 .run()
105 })
106 }
107
108 return tempFixturePath
109}
110
837666fe
RK
111async function generateVideoWithFramerate (fps = 60) {
112 const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true)
113
114 await ensureDir(dirname(tempFixturePath))
115
116 const exists = await pathExists(tempFixturePath)
117 if (!exists) {
a1587156 118 return new Promise<string>((res, rej) => {
837666fe 119 ffmpeg()
c7f36e4f 120 .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ])
837666fe
RK
121 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
122 .outputOptions([ `-r ${fps}` ])
123 .output(tempFixturePath)
124 .on('error', rej)
125 .on('end', () => res(tempFixturePath))
126 .run()
127 })
128 }
129
130 return tempFixturePath
131}
132
d218e7de
C
133async function getFileSize (path: string) {
134 const stats = await stat(path)
135
136 return stats.size
137}
138
0e1dc3e7
C
139// ---------------------------------------------------------------------------
140
141export {
0e1dc3e7
C
142 dateIsValid,
143 wait,
b488ba1e 144 areHttpImportTestsDisabled,
e2600d8b 145 buildServerDirectory,
26d21b78 146 webtorrentAdd,
d218e7de 147 getFileSize,
f05a1c30 148 immutableAssign,
9ee83eb9 149 testImage,
ac81d1a0 150 buildAbsoluteFixturePath,
74cd011b 151 root,
837666fe
RK
152 generateHighBitrateVideo,
153 generateVideoWithFramerate
0e1dc3e7 154}