]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/tests/api/server/plugins.ts
Automatically rebuild native modules on ABI change
[github/Chocobozzz/PeerTube.git] / server / tests / api / server / plugins.ts
... / ...
CommitLineData
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { pathExists, remove } from 'fs-extra'
6import { join } from 'path'
7import { testHelloWorldRegisteredSettings } from '@server/tests/shared'
8import { wait } from '@shared/core-utils'
9import { HttpStatusCode, PluginType } from '@shared/models'
10import {
11 cleanupTests,
12 createSingleServer,
13 killallServers,
14 makeGetRequest,
15 PeerTubeServer,
16 PluginsCommand,
17 setAccessTokensToServers
18} from '@shared/server-commands'
19
20const expect = chai.expect
21
22describe('Test plugins', function () {
23 let server: PeerTubeServer = null
24 let command: PluginsCommand
25
26 before(async function () {
27 this.timeout(30000)
28
29 const configOverride = {
30 plugins: {
31 index: { check_latest_versions_interval: '5 seconds' }
32 }
33 }
34 server = await createSingleServer(1, configOverride)
35 await setAccessTokensToServers([ server ])
36
37 command = server.plugins
38 })
39
40 it('Should list and search available plugins and themes', async function () {
41 this.timeout(30000)
42
43 {
44 const body = await command.listAvailable({
45 count: 1,
46 start: 0,
47 pluginType: PluginType.THEME,
48 search: 'background-red'
49 })
50
51 expect(body.total).to.be.at.least(1)
52 expect(body.data).to.have.lengthOf(1)
53 }
54
55 {
56 const body1 = await command.listAvailable({
57 count: 2,
58 start: 0,
59 sort: 'npmName'
60 })
61 expect(body1.total).to.be.at.least(2)
62
63 const data1 = body1.data
64 expect(data1).to.have.lengthOf(2)
65
66 const body2 = await command.listAvailable({
67 count: 2,
68 start: 0,
69 sort: '-npmName'
70 })
71 expect(body2.total).to.be.at.least(2)
72
73 const data2 = body2.data
74 expect(data2).to.have.lengthOf(2)
75
76 expect(data1[0].npmName).to.not.equal(data2[0].npmName)
77 }
78
79 {
80 const body = await command.listAvailable({
81 count: 10,
82 start: 0,
83 pluginType: PluginType.THEME,
84 search: 'background-red',
85 currentPeerTubeEngine: '1.0.0'
86 })
87
88 const p = body.data.find(p => p.npmName === 'peertube-theme-background-red')
89 expect(p).to.be.undefined
90 }
91 })
92
93 it('Should install a plugin and a theme', async function () {
94 this.timeout(30000)
95
96 await command.install({ npmName: 'peertube-plugin-hello-world' })
97 await command.install({ npmName: 'peertube-theme-background-red' })
98 })
99
100 it('Should have the plugin loaded in the configuration', async function () {
101 for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) {
102 const theme = config.theme.registered.find(r => r.name === 'background-red')
103 expect(theme).to.not.be.undefined
104 expect(theme.npmName).to.equal('peertube-theme-background-red')
105
106 const plugin = config.plugin.registered.find(r => r.name === 'hello-world')
107 expect(plugin).to.not.be.undefined
108 expect(plugin.npmName).to.equal('peertube-plugin-hello-world')
109 }
110 })
111
112 it('Should update the default theme in the configuration', async function () {
113 await server.config.updateCustomSubConfig({
114 newConfig: {
115 theme: { default: 'background-red' }
116 }
117 })
118
119 for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) {
120 expect(config.theme.default).to.equal('background-red')
121 }
122 })
123
124 it('Should update my default theme', async function () {
125 await server.users.updateMe({ theme: 'background-red' })
126
127 const user = await server.users.getMyInfo()
128 expect(user.theme).to.equal('background-red')
129 })
130
131 it('Should list plugins and themes', async function () {
132 {
133 const body = await command.list({
134 count: 1,
135 start: 0,
136 pluginType: PluginType.THEME
137 })
138 expect(body.total).to.be.at.least(1)
139
140 const data = body.data
141 expect(data).to.have.lengthOf(1)
142 expect(data[0].name).to.equal('background-red')
143 }
144
145 {
146 const { data } = await command.list({
147 count: 2,
148 start: 0,
149 sort: 'name'
150 })
151
152 expect(data[0].name).to.equal('background-red')
153 expect(data[1].name).to.equal('hello-world')
154 }
155
156 {
157 const body = await command.list({
158 count: 2,
159 start: 1,
160 sort: 'name'
161 })
162
163 expect(body.data[0].name).to.equal('hello-world')
164 }
165 })
166
167 it('Should get registered settings', async function () {
168 await testHelloWorldRegisteredSettings(server)
169 })
170
171 it('Should get public settings', async function () {
172 const body = await command.getPublicSettings({ npmName: 'peertube-plugin-hello-world' })
173 const publicSettings = body.publicSettings
174
175 expect(Object.keys(publicSettings)).to.have.lengthOf(1)
176 expect(Object.keys(publicSettings)).to.deep.equal([ 'user-name' ])
177 expect(publicSettings['user-name']).to.be.null
178 })
179
180 it('Should update the settings', async function () {
181 const settings = {
182 'admin-name': 'Cid'
183 }
184
185 await command.updateSettings({
186 npmName: 'peertube-plugin-hello-world',
187 settings
188 })
189 })
190
191 it('Should have watched settings changes', async function () {
192 this.timeout(10000)
193
194 await server.servers.waitUntilLog('Settings changed!')
195 })
196
197 it('Should get a plugin and a theme', async function () {
198 {
199 const plugin = await command.get({ npmName: 'peertube-plugin-hello-world' })
200
201 expect(plugin.type).to.equal(PluginType.PLUGIN)
202 expect(plugin.name).to.equal('hello-world')
203 expect(plugin.description).to.exist
204 expect(plugin.homepage).to.exist
205 expect(plugin.uninstalled).to.be.false
206 expect(plugin.enabled).to.be.true
207 expect(plugin.description).to.exist
208 expect(plugin.version).to.exist
209 expect(plugin.peertubeEngine).to.exist
210 expect(plugin.createdAt).to.exist
211
212 expect(plugin.settings).to.not.be.undefined
213 expect(plugin.settings['admin-name']).to.equal('Cid')
214 }
215
216 {
217 const plugin = await command.get({ npmName: 'peertube-theme-background-red' })
218
219 expect(plugin.type).to.equal(PluginType.THEME)
220 expect(plugin.name).to.equal('background-red')
221 expect(plugin.description).to.exist
222 expect(plugin.homepage).to.exist
223 expect(plugin.uninstalled).to.be.false
224 expect(plugin.enabled).to.be.true
225 expect(plugin.description).to.exist
226 expect(plugin.version).to.exist
227 expect(plugin.peertubeEngine).to.exist
228 expect(plugin.createdAt).to.exist
229
230 expect(plugin.settings).to.be.null
231 }
232 })
233
234 it('Should update the plugin and the theme', async function () {
235 this.timeout(180000)
236
237 // Wait the scheduler that get the latest plugins versions
238 await wait(6000)
239
240 async function testUpdate (type: 'plugin' | 'theme', name: string) {
241 // Fake update our plugin version
242 await server.sql.setPluginVersion(name, '0.0.1')
243
244 // Fake update package.json
245 const packageJSON = await command.getPackageJSON(`peertube-${type}-${name}`)
246 const oldVersion = packageJSON.version
247
248 packageJSON.version = '0.0.1'
249 await command.updatePackageJSON(`peertube-${type}-${name}`, packageJSON)
250
251 // Restart the server to take into account this change
252 await killallServers([ server ])
253 await server.run()
254
255 const checkConfig = async (version: string) => {
256 for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) {
257 expect(config[type].registered.find(r => r.name === name).version).to.equal(version)
258 }
259 }
260
261 const getPluginFromAPI = async () => {
262 const body = await command.list({ pluginType: type === 'plugin' ? PluginType.PLUGIN : PluginType.THEME })
263
264 return body.data.find(p => p.name === name)
265 }
266
267 {
268 const plugin = await getPluginFromAPI()
269 expect(plugin.version).to.equal('0.0.1')
270 expect(plugin.latestVersion).to.exist
271 expect(plugin.latestVersion).to.not.equal('0.0.1')
272
273 await checkConfig('0.0.1')
274 }
275
276 {
277 await command.update({ npmName: `peertube-${type}-${name}` })
278
279 const plugin = await getPluginFromAPI()
280 expect(plugin.version).to.equal(oldVersion)
281
282 const updatedPackageJSON = await command.getPackageJSON(`peertube-${type}-${name}`)
283 expect(updatedPackageJSON.version).to.equal(oldVersion)
284
285 await checkConfig(oldVersion)
286 }
287 }
288
289 await testUpdate('theme', 'background-red')
290 await testUpdate('plugin', 'hello-world')
291 })
292
293 it('Should uninstall the plugin', async function () {
294 await command.uninstall({ npmName: 'peertube-plugin-hello-world' })
295
296 const body = await command.list({ pluginType: PluginType.PLUGIN })
297 expect(body.total).to.equal(0)
298 expect(body.data).to.have.lengthOf(0)
299 })
300
301 it('Should list uninstalled plugins', async function () {
302 const body = await command.list({ pluginType: PluginType.PLUGIN, uninstalled: true })
303 expect(body.total).to.equal(1)
304 expect(body.data).to.have.lengthOf(1)
305
306 const plugin = body.data[0]
307 expect(plugin.name).to.equal('hello-world')
308 expect(plugin.enabled).to.be.false
309 expect(plugin.uninstalled).to.be.true
310 })
311
312 it('Should uninstall the theme', async function () {
313 await command.uninstall({ npmName: 'peertube-theme-background-red' })
314 })
315
316 it('Should have updated the configuration', async function () {
317 for (const config of [ await server.config.getConfig(), await server.config.getIndexHTMLConfig() ]) {
318 expect(config.theme.default).to.equal('default')
319
320 const theme = config.theme.registered.find(r => r.name === 'background-red')
321 expect(theme).to.be.undefined
322
323 const plugin = config.plugin.registered.find(r => r.name === 'hello-world')
324 expect(plugin).to.be.undefined
325 }
326 })
327
328 it('Should have updated the user theme', async function () {
329 const user = await server.users.getMyInfo()
330 expect(user.theme).to.equal('instance-default')
331 })
332
333 it('Should not install a broken plugin', async function () {
334 this.timeout(60000)
335
336 async function check () {
337 const body = await command.list({ pluginType: PluginType.PLUGIN })
338 const plugins = body.data
339 expect(plugins.find(p => p.name === 'test-broken')).to.not.exist
340 }
341
342 await command.install({
343 path: PluginsCommand.getPluginTestPath('-broken'),
344 expectedStatus: HttpStatusCode.BAD_REQUEST_400
345 })
346
347 await check()
348
349 await killallServers([ server ])
350 await server.run()
351
352 await check()
353 })
354
355 it('Should rebuild native modules on Node ABI change', async function () {
356 await command.install({ path: PluginsCommand.getPluginTestPath('-native') })
357
358 await makeGetRequest({
359 url: server.url,
360 path: '/plugins/test-native/router',
361 expectedStatus: HttpStatusCode.NO_CONTENT_204
362 })
363
364 const query = `UPDATE "application" SET "nodeABIVersion" = 1`
365 await server.sql.updateQuery(query)
366
367 const baseNativeModule = server.servers.buildDirectory(join('plugins', 'node_modules', 'a-native-example'))
368 await remove(join(baseNativeModule, 'build'))
369 await remove(join(baseNativeModule, 'prebuilds'))
370
371 await server.kill()
372 await server.run()
373
374 await pathExists(join(baseNativeModule, 'build'))
375 await pathExists(join(baseNativeModule, 'prebuilds'))
376
377 await makeGetRequest({
378 url: server.url,
379 path: '/plugins/test-native/router',
380 expectedStatus: HttpStatusCode.NO_CONTENT_204
381 })
382 })
383
384 after(async function () {
385 await cleanupTests([ server ])
386 })
387})