diff options
Diffstat (limited to 'server/tests')
-rw-r--r-- | server/tests/client.ts | 4 | ||||
-rw-r--r-- | server/tests/feeds/feeds.ts | 361 | ||||
-rw-r--r-- | server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/main.js | 82 | ||||
-rw-r--r-- | server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/package.json | 19 | ||||
-rw-r--r-- | server/tests/fixtures/peertube-plugin-test/main.js | 1 | ||||
-rw-r--r-- | server/tests/plugins/action-hooks.ts | 31 |
6 files changed, 381 insertions, 117 deletions
diff --git a/server/tests/client.ts b/server/tests/client.ts index 9a20c2a10..e84251561 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -172,7 +172,7 @@ describe('Test a client controllers', function () { | |||
172 | expect(text).to.contain(`<meta property="og:title" content="${account.displayName}" />`) | 172 | expect(text).to.contain(`<meta property="og:title" content="${account.displayName}" />`) |
173 | expect(text).to.contain(`<meta property="og:description" content="${account.description}" />`) | 173 | expect(text).to.contain(`<meta property="og:description" content="${account.description}" />`) |
174 | expect(text).to.contain('<meta property="og:type" content="website" />') | 174 | expect(text).to.contain('<meta property="og:type" content="website" />') |
175 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].store.user.username}" />`) | 175 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/a/${servers[0].store.user.username}" />`) |
176 | } | 176 | } |
177 | 177 | ||
178 | async function channelPageTest (path: string) { | 178 | async function channelPageTest (path: string) { |
@@ -182,7 +182,7 @@ describe('Test a client controllers', function () { | |||
182 | expect(text).to.contain(`<meta property="og:title" content="${servers[0].store.channel.displayName}" />`) | 182 | expect(text).to.contain(`<meta property="og:title" content="${servers[0].store.channel.displayName}" />`) |
183 | expect(text).to.contain(`<meta property="og:description" content="${channelDescription}" />`) | 183 | expect(text).to.contain(`<meta property="og:description" content="${channelDescription}" />`) |
184 | expect(text).to.contain('<meta property="og:type" content="website" />') | 184 | expect(text).to.contain('<meta property="og:type" content="website" />') |
185 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].store.channel.name}" />`) | 185 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/c/${servers[0].store.channel.name}" />`) |
186 | } | 186 | } |
187 | 187 | ||
188 | async function watchVideoPageTest (path: string) { | 188 | async function watchVideoPageTest (path: string) { |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index ecd1badc1..57eefff6d 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -11,6 +11,7 @@ import { | |||
11 | makeGetRequest, | 11 | makeGetRequest, |
12 | makeRawRequest, | 12 | makeRawRequest, |
13 | PeerTubeServer, | 13 | PeerTubeServer, |
14 | PluginsCommand, | ||
14 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
15 | setDefaultChannelAvatar, | 16 | setDefaultChannelAvatar, |
16 | stopFfmpeg, | 17 | stopFfmpeg, |
@@ -26,12 +27,15 @@ const expect = chai.expect | |||
26 | describe('Test syndication feeds', () => { | 27 | describe('Test syndication feeds', () => { |
27 | let servers: PeerTubeServer[] = [] | 28 | let servers: PeerTubeServer[] = [] |
28 | let serverHLSOnly: PeerTubeServer | 29 | let serverHLSOnly: PeerTubeServer |
30 | |||
29 | let userAccessToken: string | 31 | let userAccessToken: string |
30 | let rootAccountId: number | 32 | let rootAccountId: number |
31 | let rootChannelId: number | 33 | let rootChannelId: number |
34 | |||
32 | let userAccountId: number | 35 | let userAccountId: number |
33 | let userChannelId: number | 36 | let userChannelId: number |
34 | let userFeedToken: string | 37 | let userFeedToken: string |
38 | |||
35 | let liveId: string | 39 | let liveId: string |
36 | 40 | ||
37 | before(async function () { | 41 | before(async function () { |
@@ -93,7 +97,11 @@ describe('Test syndication feeds', () => { | |||
93 | await servers[0].comments.createThread({ videoId: id, text: 'comment on unlisted video' }) | 97 | await servers[0].comments.createThread({ videoId: id, text: 'comment on unlisted video' }) |
94 | } | 98 | } |
95 | 99 | ||
96 | await waitJobs(servers) | 100 | await serverHLSOnly.videos.upload({ attributes: { name: 'hls only video' } }) |
101 | |||
102 | await waitJobs([ ...servers, serverHLSOnly ]) | ||
103 | |||
104 | await servers[0].plugins.install({ path: PluginsCommand.getPluginTestPath('-podcast-custom-tags') }) | ||
97 | }) | 105 | }) |
98 | 106 | ||
99 | describe('All feed', function () { | 107 | describe('All feed', function () { |
@@ -108,6 +116,11 @@ describe('Test syndication feeds', () => { | |||
108 | } | 116 | } |
109 | }) | 117 | }) |
110 | 118 | ||
119 | it('Should be well formed XML (covers Podcast endpoint)', async function () { | ||
120 | const podcast = await servers[0].feed.getPodcastXML({ ignoreCache: true, channelId: rootChannelId }) | ||
121 | expect(podcast).xml.to.be.valid() | ||
122 | }) | ||
123 | |||
111 | it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { | 124 | it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { |
112 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { | 125 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { |
113 | const jsonText = await servers[0].feed.getJSON({ feed, ignoreCache: true }) | 126 | const jsonText = await servers[0].feed.getJSON({ feed, ignoreCache: true }) |
@@ -153,168 +166,290 @@ describe('Test syndication feeds', () => { | |||
153 | 166 | ||
154 | describe('Videos feed', function () { | 167 | describe('Videos feed', function () { |
155 | 168 | ||
156 | it('Should contain a valid enclosure (covers RSS 2.0 endpoint)', async function () { | 169 | describe('Podcast feed', function () { |
157 | for (const server of servers) { | 170 | |
158 | const rss = await server.feed.getXML({ feed: 'videos', ignoreCache: true }) | 171 | it('Should contain a valid podcast:alternateEnclosure', async function () { |
172 | // Since podcast feeds should only work on the server they originate on, | ||
173 | // only test the first server where the videos reside | ||
174 | const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) | ||
159 | expect(XMLValidator.validate(rss)).to.be.true | 175 | expect(XMLValidator.validate(rss)).to.be.true |
160 | 176 | ||
161 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) | 177 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) |
162 | const xmlDoc = parser.parse(rss) | 178 | const xmlDoc = parser.parse(rss) |
163 | 179 | ||
164 | const enclosure = xmlDoc.rss.channel.item[0].enclosure | 180 | const enclosure = xmlDoc.rss.channel.item.enclosure |
165 | expect(enclosure).to.exist | 181 | expect(enclosure).to.exist |
182 | const alternateEnclosure = xmlDoc.rss.channel.item['podcast:alternateEnclosure'] | ||
183 | expect(alternateEnclosure).to.exist | ||
184 | |||
185 | expect(alternateEnclosure['@_type']).to.equal('video/webm') | ||
186 | expect(alternateEnclosure['@_length']).to.equal(218910) | ||
187 | expect(alternateEnclosure['@_lang']).to.equal('zh') | ||
188 | expect(alternateEnclosure['@_title']).to.equal('720p') | ||
189 | expect(alternateEnclosure['@_default']).to.equal(true) | ||
190 | |||
191 | expect(alternateEnclosure['podcast:source'][0]['@_uri']).to.contain('-720.webm') | ||
192 | expect(alternateEnclosure['podcast:source'][0]['@_uri']).to.equal(enclosure['@_url']) | ||
193 | expect(alternateEnclosure['podcast:source'][1]['@_uri']).to.contain('-720.torrent') | ||
194 | expect(alternateEnclosure['podcast:source'][1]['@_contentType']).to.equal('application/x-bittorrent') | ||
195 | expect(alternateEnclosure['podcast:source'][2]['@_uri']).to.contain('magnet:?') | ||
196 | }) | ||
166 | 197 | ||
167 | expect(enclosure['@_type']).to.equal('video/webm') | 198 | it('Should contain a valid podcast:alternateEnclosure with HLS only', async function () { |
168 | expect(enclosure['@_length']).to.equal(218910) | 199 | const rss = await serverHLSOnly.feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) |
169 | expect(enclosure['@_url']).to.contain('-720.webm') | 200 | expect(XMLValidator.validate(rss)).to.be.true |
170 | } | ||
171 | }) | ||
172 | 201 | ||
173 | it('Should contain a valid \'attachments\' object (covers JSON feed 1.0 endpoint)', async function () { | 202 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) |
174 | for (const server of servers) { | 203 | const xmlDoc = parser.parse(rss) |
175 | const json = await server.feed.getJSON({ feed: 'videos', ignoreCache: true }) | 204 | |
176 | const jsonObj = JSON.parse(json) | 205 | const enclosure = xmlDoc.rss.channel.item.enclosure |
177 | expect(jsonObj.items.length).to.be.equal(2) | 206 | const alternateEnclosure = xmlDoc.rss.channel.item['podcast:alternateEnclosure'] |
178 | expect(jsonObj.items[0].attachments).to.exist | 207 | expect(alternateEnclosure).to.exist |
179 | expect(jsonObj.items[0].attachments.length).to.be.eq(1) | 208 | |
180 | expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent') | 209 | expect(alternateEnclosure['@_type']).to.equal('application/x-mpegURL') |
181 | expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910) | 210 | expect(alternateEnclosure['@_lang']).to.equal('zh') |
182 | expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent') | 211 | expect(alternateEnclosure['@_title']).to.equal('HLS') |
183 | } | 212 | expect(alternateEnclosure['@_default']).to.equal(true) |
213 | |||
214 | expect(alternateEnclosure['podcast:source']['@_uri']).to.contain('-master.m3u8') | ||
215 | expect(alternateEnclosure['podcast:source']['@_uri']).to.equal(enclosure['@_url']) | ||
216 | }) | ||
217 | |||
218 | it('Should contain a valid podcast:socialInteract', async function () { | ||
219 | const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) | ||
220 | expect(XMLValidator.validate(rss)).to.be.true | ||
221 | |||
222 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) | ||
223 | const xmlDoc = parser.parse(rss) | ||
224 | |||
225 | const item = xmlDoc.rss.channel.item | ||
226 | const socialInteract = item['podcast:socialInteract'] | ||
227 | expect(socialInteract).to.exist | ||
228 | expect(socialInteract['@_protocol']).to.equal('activitypub') | ||
229 | expect(socialInteract['@_uri']).to.exist | ||
230 | expect(socialInteract['@_accountUrl']).to.exist | ||
231 | }) | ||
232 | |||
233 | it('Should contain a valid support custom tags for plugins', async function () { | ||
234 | const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: userChannelId }) | ||
235 | expect(XMLValidator.validate(rss)).to.be.true | ||
236 | |||
237 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) | ||
238 | const xmlDoc = parser.parse(rss) | ||
239 | |||
240 | const fooTag = xmlDoc.rss.channel.fooTag | ||
241 | expect(fooTag).to.exist | ||
242 | expect(fooTag['@_bar']).to.equal('baz') | ||
243 | expect(fooTag['#text']).to.equal(42) | ||
244 | |||
245 | const bizzBuzzItem = xmlDoc.rss.channel['biz:buzzItem'] | ||
246 | expect(bizzBuzzItem).to.exist | ||
247 | |||
248 | let nestedTag = bizzBuzzItem.nestedTag | ||
249 | expect(nestedTag).to.exist | ||
250 | expect(nestedTag).to.equal('example nested tag') | ||
251 | |||
252 | const item = xmlDoc.rss.channel.item | ||
253 | const fizzTag = item.fizzTag | ||
254 | expect(fizzTag).to.exist | ||
255 | expect(fizzTag['@_bar']).to.equal('baz') | ||
256 | expect(fizzTag['#text']).to.equal(21) | ||
257 | |||
258 | const bizzBuzz = item['biz:buzz'] | ||
259 | expect(bizzBuzz).to.exist | ||
260 | |||
261 | nestedTag = bizzBuzz.nestedTag | ||
262 | expect(nestedTag).to.exist | ||
263 | expect(nestedTag).to.equal('example nested tag') | ||
264 | }) | ||
265 | |||
266 | it('Should contain a valid podcast:liveItem for live streams', async function () { | ||
267 | this.timeout(120000) | ||
268 | |||
269 | const { uuid } = await servers[0].live.create({ | ||
270 | fields: { | ||
271 | name: 'live-0', | ||
272 | privacy: VideoPrivacy.PUBLIC, | ||
273 | channelId: rootChannelId, | ||
274 | permanentLive: false | ||
275 | } | ||
276 | }) | ||
277 | liveId = uuid | ||
278 | |||
279 | const ffmpeg = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveId, copyCodecs: true, fixtureName: 'video_short.mp4' }) | ||
280 | await servers[0].live.waitUntilPublished({ videoId: liveId }) | ||
281 | |||
282 | const rss = await servers[0].feed.getPodcastXML({ ignoreCache: false, channelId: rootChannelId }) | ||
283 | expect(XMLValidator.validate(rss)).to.be.true | ||
284 | |||
285 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) | ||
286 | const xmlDoc = parser.parse(rss) | ||
287 | const liveItem = xmlDoc.rss.channel['podcast:liveItem'] | ||
288 | expect(liveItem.title).to.equal('live-0') | ||
289 | expect(liveItem['@_status']).to.equal('live') | ||
290 | |||
291 | const enclosure = liveItem.enclosure | ||
292 | const alternateEnclosure = liveItem['podcast:alternateEnclosure'] | ||
293 | expect(alternateEnclosure).to.exist | ||
294 | expect(alternateEnclosure['@_type']).to.equal('application/x-mpegURL') | ||
295 | expect(alternateEnclosure['@_title']).to.equal('HLS live stream') | ||
296 | expect(alternateEnclosure['@_default']).to.equal(true) | ||
297 | |||
298 | expect(alternateEnclosure['podcast:source']['@_uri']).to.contain('/master.m3u8') | ||
299 | expect(alternateEnclosure['podcast:source']['@_uri']).to.equal(enclosure['@_url']) | ||
300 | |||
301 | await stopFfmpeg(ffmpeg) | ||
302 | |||
303 | await servers[0].live.waitUntilEnded({ videoId: liveId }) | ||
304 | |||
305 | await waitJobs(servers) | ||
306 | }) | ||
184 | }) | 307 | }) |
185 | 308 | ||
186 | it('Should filter by account', async function () { | 309 | describe('JSON feed', function () { |
187 | { | ||
188 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { accountId: rootAccountId }, ignoreCache: true }) | ||
189 | const jsonObj = JSON.parse(json) | ||
190 | expect(jsonObj.items.length).to.be.equal(1) | ||
191 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | ||
192 | expect(jsonObj.items[0].author.name).to.equal('Main root channel') | ||
193 | } | ||
194 | 310 | ||
195 | { | 311 | it('Should contain a valid \'attachments\' object', async function () { |
196 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { accountId: userAccountId }, ignoreCache: true }) | 312 | for (const server of servers) { |
197 | const jsonObj = JSON.parse(json) | 313 | const json = await server.feed.getJSON({ feed: 'videos', ignoreCache: true }) |
198 | expect(jsonObj.items.length).to.be.equal(1) | 314 | const jsonObj = JSON.parse(json) |
199 | expect(jsonObj.items[0].title).to.equal('user video') | 315 | expect(jsonObj.items.length).to.be.equal(2) |
200 | expect(jsonObj.items[0].author.name).to.equal('Main john channel') | 316 | expect(jsonObj.items[0].attachments).to.exist |
201 | } | 317 | expect(jsonObj.items[0].attachments.length).to.be.eq(1) |
318 | expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent') | ||
319 | expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910) | ||
320 | expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent') | ||
321 | } | ||
322 | }) | ||
202 | 323 | ||
203 | for (const server of servers) { | 324 | it('Should filter by account', async function () { |
204 | { | 325 | { |
205 | const json = await server.feed.getJSON({ feed: 'videos', query: { accountName: 'root@' + servers[0].host }, ignoreCache: true }) | 326 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { accountId: rootAccountId }, ignoreCache: true }) |
206 | const jsonObj = JSON.parse(json) | 327 | const jsonObj = JSON.parse(json) |
207 | expect(jsonObj.items.length).to.be.equal(1) | 328 | expect(jsonObj.items.length).to.be.equal(1) |
208 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | 329 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
330 | expect(jsonObj.items[0].author.name).to.equal('Main root channel') | ||
209 | } | 331 | } |
210 | 332 | ||
211 | { | 333 | { |
212 | const json = await server.feed.getJSON({ feed: 'videos', query: { accountName: 'john@' + servers[0].host }, ignoreCache: true }) | 334 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { accountId: userAccountId }, ignoreCache: true }) |
213 | const jsonObj = JSON.parse(json) | 335 | const jsonObj = JSON.parse(json) |
214 | expect(jsonObj.items.length).to.be.equal(1) | 336 | expect(jsonObj.items.length).to.be.equal(1) |
215 | expect(jsonObj.items[0].title).to.equal('user video') | 337 | expect(jsonObj.items[0].title).to.equal('user video') |
338 | expect(jsonObj.items[0].author.name).to.equal('Main john channel') | ||
216 | } | 339 | } |
217 | } | ||
218 | }) | ||
219 | 340 | ||
220 | it('Should filter by video channel', async function () { | 341 | for (const server of servers) { |
221 | { | 342 | { |
222 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) | 343 | const json = await server.feed.getJSON({ feed: 'videos', query: { accountName: 'root@' + servers[0].host }, ignoreCache: true }) |
223 | const jsonObj = JSON.parse(json) | 344 | const jsonObj = JSON.parse(json) |
224 | expect(jsonObj.items.length).to.be.equal(1) | 345 | expect(jsonObj.items.length).to.be.equal(1) |
225 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | 346 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
226 | expect(jsonObj.items[0].author.name).to.equal('Main root channel') | 347 | } |
227 | } | 348 | |
228 | 349 | { | |
229 | { | 350 | const json = await server.feed.getJSON({ feed: 'videos', query: { accountName: 'john@' + servers[0].host }, ignoreCache: true }) |
230 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: userChannelId }, ignoreCache: true }) | 351 | const jsonObj = JSON.parse(json) |
231 | const jsonObj = JSON.parse(json) | 352 | expect(jsonObj.items.length).to.be.equal(1) |
232 | expect(jsonObj.items.length).to.be.equal(1) | 353 | expect(jsonObj.items[0].title).to.equal('user video') |
233 | expect(jsonObj.items[0].title).to.equal('user video') | 354 | } |
234 | expect(jsonObj.items[0].author.name).to.equal('Main john channel') | 355 | } |
235 | } | 356 | }) |
236 | 357 | ||
237 | for (const server of servers) { | 358 | it('Should filter by video channel', async function () { |
238 | { | 359 | { |
239 | const query = { videoChannelName: 'root_channel@' + servers[0].host } | 360 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) |
240 | const json = await server.feed.getJSON({ feed: 'videos', query, ignoreCache: true }) | ||
241 | const jsonObj = JSON.parse(json) | 361 | const jsonObj = JSON.parse(json) |
242 | expect(jsonObj.items.length).to.be.equal(1) | 362 | expect(jsonObj.items.length).to.be.equal(1) |
243 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | 363 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
364 | expect(jsonObj.items[0].author.name).to.equal('Main root channel') | ||
244 | } | 365 | } |
245 | 366 | ||
246 | { | 367 | { |
247 | const query = { videoChannelName: 'john_channel@' + servers[0].host } | 368 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: userChannelId }, ignoreCache: true }) |
248 | const json = await server.feed.getJSON({ feed: 'videos', query, ignoreCache: true }) | ||
249 | const jsonObj = JSON.parse(json) | 369 | const jsonObj = JSON.parse(json) |
250 | expect(jsonObj.items.length).to.be.equal(1) | 370 | expect(jsonObj.items.length).to.be.equal(1) |
251 | expect(jsonObj.items[0].title).to.equal('user video') | 371 | expect(jsonObj.items[0].title).to.equal('user video') |
372 | expect(jsonObj.items[0].author.name).to.equal('Main john channel') | ||
252 | } | 373 | } |
253 | } | ||
254 | }) | ||
255 | 374 | ||
256 | it('Should correctly have videos feed with HLS only', async function () { | 375 | for (const server of servers) { |
257 | this.timeout(120000) | 376 | { |
258 | 377 | const query = { videoChannelName: 'root_channel@' + servers[0].host } | |
259 | await serverHLSOnly.videos.upload({ attributes: { name: 'hls only video' } }) | 378 | const json = await server.feed.getJSON({ feed: 'videos', query, ignoreCache: true }) |
379 | const jsonObj = JSON.parse(json) | ||
380 | expect(jsonObj.items.length).to.be.equal(1) | ||
381 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | ||
382 | } | ||
383 | |||
384 | { | ||
385 | const query = { videoChannelName: 'john_channel@' + servers[0].host } | ||
386 | const json = await server.feed.getJSON({ feed: 'videos', query, ignoreCache: true }) | ||
387 | const jsonObj = JSON.parse(json) | ||
388 | expect(jsonObj.items.length).to.be.equal(1) | ||
389 | expect(jsonObj.items[0].title).to.equal('user video') | ||
390 | } | ||
391 | } | ||
392 | }) | ||
260 | 393 | ||
261 | await waitJobs([ serverHLSOnly ]) | 394 | it('Should correctly have videos feed with HLS only', async function () { |
395 | this.timeout(120000) | ||
262 | 396 | ||
263 | const json = await serverHLSOnly.feed.getJSON({ feed: 'videos', ignoreCache: true }) | 397 | const json = await serverHLSOnly.feed.getJSON({ feed: 'videos', ignoreCache: true }) |
264 | const jsonObj = JSON.parse(json) | 398 | const jsonObj = JSON.parse(json) |
265 | expect(jsonObj.items.length).to.be.equal(1) | 399 | expect(jsonObj.items.length).to.be.equal(1) |
266 | expect(jsonObj.items[0].attachments).to.exist | 400 | expect(jsonObj.items[0].attachments).to.exist |
267 | expect(jsonObj.items[0].attachments.length).to.be.eq(4) | 401 | expect(jsonObj.items[0].attachments.length).to.be.eq(4) |
268 | |||
269 | for (let i = 0; i < 4; i++) { | ||
270 | expect(jsonObj.items[0].attachments[i].mime_type).to.be.eq('application/x-bittorrent') | ||
271 | expect(jsonObj.items[0].attachments[i].size_in_bytes).to.be.greaterThan(0) | ||
272 | expect(jsonObj.items[0].attachments[i].url).to.exist | ||
273 | } | ||
274 | }) | ||
275 | 402 | ||
276 | it('Should not display waiting live videos', async function () { | 403 | for (let i = 0; i < 4; i++) { |
277 | const { uuid } = await servers[0].live.create({ | 404 | expect(jsonObj.items[0].attachments[i].mime_type).to.be.eq('application/x-bittorrent') |
278 | fields: { | 405 | expect(jsonObj.items[0].attachments[i].size_in_bytes).to.be.greaterThan(0) |
279 | name: 'live', | 406 | expect(jsonObj.items[0].attachments[i].url).to.exist |
280 | privacy: VideoPrivacy.PUBLIC, | ||
281 | channelId: rootChannelId | ||
282 | } | 407 | } |
283 | }) | 408 | }) |
284 | liveId = uuid | ||
285 | 409 | ||
286 | const json = await servers[0].feed.getJSON({ feed: 'videos', ignoreCache: true }) | 410 | it('Should not display waiting live videos', async function () { |
411 | const { uuid } = await servers[0].live.create({ | ||
412 | fields: { | ||
413 | name: 'live', | ||
414 | privacy: VideoPrivacy.PUBLIC, | ||
415 | channelId: rootChannelId | ||
416 | } | ||
417 | }) | ||
418 | liveId = uuid | ||
287 | 419 | ||
288 | const jsonObj = JSON.parse(json) | 420 | const json = await servers[0].feed.getJSON({ feed: 'videos', ignoreCache: true }) |
289 | expect(jsonObj.items.length).to.be.equal(2) | 421 | |
290 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | 422 | const jsonObj = JSON.parse(json) |
291 | expect(jsonObj.items[1].title).to.equal('user video') | 423 | expect(jsonObj.items.length).to.be.equal(2) |
292 | }) | 424 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
425 | expect(jsonObj.items[1].title).to.equal('user video') | ||
426 | }) | ||
293 | 427 | ||
294 | it('Should display published live videos', async function () { | 428 | it('Should display published live videos', async function () { |
295 | this.timeout(120000) | 429 | this.timeout(120000) |
296 | 430 | ||
297 | const ffmpeg = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveId, copyCodecs: true, fixtureName: 'video_short.mp4' }) | 431 | const ffmpeg = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveId, copyCodecs: true, fixtureName: 'video_short.mp4' }) |
298 | await servers[0].live.waitUntilPublished({ videoId: liveId }) | 432 | await servers[0].live.waitUntilPublished({ videoId: liveId }) |
299 | 433 | ||
300 | const json = await servers[0].feed.getJSON({ feed: 'videos', ignoreCache: true }) | 434 | const json = await servers[0].feed.getJSON({ feed: 'videos', ignoreCache: true }) |
301 | 435 | ||
302 | const jsonObj = JSON.parse(json) | 436 | const jsonObj = JSON.parse(json) |
303 | expect(jsonObj.items.length).to.be.equal(3) | 437 | expect(jsonObj.items.length).to.be.equal(3) |
304 | expect(jsonObj.items[0].title).to.equal('live') | 438 | expect(jsonObj.items[0].title).to.equal('live') |
305 | expect(jsonObj.items[1].title).to.equal('my super name for server 1') | 439 | expect(jsonObj.items[1].title).to.equal('my super name for server 1') |
306 | expect(jsonObj.items[2].title).to.equal('user video') | 440 | expect(jsonObj.items[2].title).to.equal('user video') |
307 | 441 | ||
308 | await stopFfmpeg(ffmpeg) | 442 | await stopFfmpeg(ffmpeg) |
309 | }) | 443 | }) |
310 | 444 | ||
311 | it('Should have the channel avatar as feed icon', async function () { | 445 | it('Should have the channel avatar as feed icon', async function () { |
312 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) | 446 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) |
313 | 447 | ||
314 | const jsonObj = JSON.parse(json) | 448 | const jsonObj = JSON.parse(json) |
315 | const imageUrl = jsonObj.icon | 449 | const imageUrl = jsonObj.icon |
316 | expect(imageUrl).to.include('/lazy-static/avatars/') | 450 | expect(imageUrl).to.include('/lazy-static/avatars/') |
317 | await makeRawRequest({ url: imageUrl, expectedStatus: HttpStatusCode.OK_200 }) | 451 | await makeRawRequest({ url: imageUrl, expectedStatus: HttpStatusCode.OK_200 }) |
452 | }) | ||
318 | }) | 453 | }) |
319 | }) | 454 | }) |
320 | 455 | ||
@@ -470,6 +605,8 @@ describe('Test syndication feeds', () => { | |||
470 | }) | 605 | }) |
471 | 606 | ||
472 | after(async function () { | 607 | after(async function () { |
608 | await servers[0].plugins.uninstall({ npmName: 'peertube-plugin-test-podcast-custom-tags' }) | ||
609 | |||
473 | await cleanupTests([ ...servers, serverHLSOnly ]) | 610 | await cleanupTests([ ...servers, serverHLSOnly ]) |
474 | }) | 611 | }) |
475 | }) | 612 | }) |
diff --git a/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/main.js b/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/main.js new file mode 100644 index 000000000..ada4a70fe --- /dev/null +++ b/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/main.js | |||
@@ -0,0 +1,82 @@ | |||
1 | async function register ({ registerHook, registerSetting, settingsManager, storageManager, peertubeHelpers }) { | ||
2 | registerHook({ | ||
3 | target: 'filter:feed.podcast.rss.create-custom-xmlns.result', | ||
4 | handler: (result, params) => { | ||
5 | return result.concat([ | ||
6 | { | ||
7 | name: "biz", | ||
8 | value: "https://example.com/biz-xmlns", | ||
9 | }, | ||
10 | ]) | ||
11 | } | ||
12 | }) | ||
13 | |||
14 | registerHook({ | ||
15 | target: 'filter:feed.podcast.channel.create-custom-tags.result', | ||
16 | handler: (result, params) => { | ||
17 | const { videoChannel } = params | ||
18 | return result.concat([ | ||
19 | { | ||
20 | name: "fooTag", | ||
21 | attributes: { "bar": "baz" }, | ||
22 | value: "42", | ||
23 | }, | ||
24 | { | ||
25 | name: "biz:videoChannel", | ||
26 | attributes: { "name": videoChannel.name, "id": videoChannel.id }, | ||
27 | }, | ||
28 | { | ||
29 | name: "biz:buzzItem", | ||
30 | value: [ | ||
31 | { | ||
32 | name: "nestedTag", | ||
33 | value: "example nested tag", | ||
34 | }, | ||
35 | ], | ||
36 | }, | ||
37 | ]) | ||
38 | } | ||
39 | }) | ||
40 | |||
41 | registerHook({ | ||
42 | target: 'filter:feed.podcast.video.create-custom-tags.result', | ||
43 | handler: (result, params) => { | ||
44 | const { video, liveItem } = params | ||
45 | return result.concat([ | ||
46 | { | ||
47 | name: "fizzTag", | ||
48 | attributes: { "bar": "baz" }, | ||
49 | value: "21", | ||
50 | }, | ||
51 | { | ||
52 | name: "biz:video", | ||
53 | attributes: { "name": video.name, "id": video.id, "isLive": liveItem }, | ||
54 | }, | ||
55 | { | ||
56 | name: "biz:buzz", | ||
57 | value: [ | ||
58 | { | ||
59 | name: "nestedTag", | ||
60 | value: "example nested tag", | ||
61 | }, | ||
62 | ], | ||
63 | } | ||
64 | ]) | ||
65 | } | ||
66 | }) | ||
67 | } | ||
68 | |||
69 | async function unregister () { | ||
70 | return | ||
71 | } | ||
72 | |||
73 | module.exports = { | ||
74 | register, | ||
75 | unregister | ||
76 | } | ||
77 | |||
78 | // ############################################################################ | ||
79 | |||
80 | function addToCount (obj) { | ||
81 | return Object.assign({}, obj, { count: obj.count + 1 }) | ||
82 | } | ||
diff --git a/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/package.json b/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/package.json new file mode 100644 index 000000000..0f5a05a79 --- /dev/null +++ b/server/tests/fixtures/peertube-plugin-test-podcast-custom-tags/package.json | |||
@@ -0,0 +1,19 @@ | |||
1 | { | ||
2 | "name": "peertube-plugin-test-podcast-custom-tags", | ||
3 | "version": "0.0.1", | ||
4 | "description": "Plugin test custom tags in Podcast RSS feeds", | ||
5 | "engine": { | ||
6 | "peertube": ">=1.3.0" | ||
7 | }, | ||
8 | "keywords": [ | ||
9 | "peertube", | ||
10 | "plugin" | ||
11 | ], | ||
12 | "homepage": "https://github.com/Chocobozzz/PeerTube", | ||
13 | "author": "Chocobozzz", | ||
14 | "bugs": "https://github.com/Chocobozzz/PeerTube/issues", | ||
15 | "library": "./main.js", | ||
16 | "staticDirs": {}, | ||
17 | "css": [], | ||
18 | "clientScripts": [] | ||
19 | } | ||
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index 36dd08d27..17032f6d9 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js | |||
@@ -14,6 +14,7 @@ async function register ({ registerHook, registerSetting, settingsManager, stora | |||
14 | 'action:api.video-channel.deleted', | 14 | 'action:api.video-channel.deleted', |
15 | 15 | ||
16 | 'action:api.live-video.created', | 16 | 'action:api.live-video.created', |
17 | 'action:live.video.state.updated', | ||
17 | 18 | ||
18 | 'action:api.video-thread.created', | 19 | 'action:api.video-thread.created', |
19 | 'action:api.video-comment-reply.created', | 20 | 'action:api.video-comment-reply.created', |
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index e8d03ee0f..34b4e1891 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts | |||
@@ -9,7 +9,9 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | PluginsCommand, | 10 | PluginsCommand, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | setDefaultVideoChannel | 12 | setDefaultVideoChannel, |
13 | stopFfmpeg, | ||
14 | waitJobs | ||
13 | } from '@shared/server-commands' | 15 | } from '@shared/server-commands' |
14 | 16 | ||
15 | describe('Test plugin action hooks', function () { | 17 | describe('Test plugin action hooks', function () { |
@@ -17,8 +19,8 @@ describe('Test plugin action hooks', function () { | |||
17 | let videoUUID: string | 19 | let videoUUID: string |
18 | let threadId: number | 20 | let threadId: number |
19 | 21 | ||
20 | function checkHook (hook: ServerHookName, strictCount = true) { | 22 | function checkHook (hook: ServerHookName, strictCount = true, count = 1) { |
21 | return servers[0].servers.waitUntilLog('Run hook ' + hook, 1, strictCount) | 23 | return servers[0].servers.waitUntilLog('Run hook ' + hook, count, strictCount) |
22 | } | 24 | } |
23 | 25 | ||
24 | before(async function () { | 26 | before(async function () { |
@@ -115,6 +117,29 @@ describe('Test plugin action hooks', function () { | |||
115 | 117 | ||
116 | await checkHook('action:api.live-video.created') | 118 | await checkHook('action:api.live-video.created') |
117 | }) | 119 | }) |
120 | |||
121 | it('Should run action:live.video.state.updated', async function () { | ||
122 | this.timeout(60000) | ||
123 | |||
124 | const attributes = { | ||
125 | name: 'live', | ||
126 | privacy: VideoPrivacy.PUBLIC, | ||
127 | channelId: servers[0].store.channel.id | ||
128 | } | ||
129 | |||
130 | const { uuid: liveVideoId } = await servers[0].live.create({ fields: attributes }) | ||
131 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoId }) | ||
132 | await servers[0].live.waitUntilPublished({ videoId: liveVideoId }) | ||
133 | await waitJobs(servers) | ||
134 | |||
135 | await checkHook('action:live.video.state.updated', true, 1) | ||
136 | |||
137 | await stopFfmpeg(ffmpegCommand) | ||
138 | await servers[0].live.waitUntilEnded({ videoId: liveVideoId }) | ||
139 | await waitJobs(servers) | ||
140 | |||
141 | await checkHook('action:live.video.state.updated', true, 2) | ||
142 | }) | ||
118 | }) | 143 | }) |
119 | 144 | ||
120 | describe('Comments hooks', function () { | 145 | describe('Comments hooks', function () { |