aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api')
-rw-r--r--server/tests/api/live/index.ts2
-rw-r--r--server/tests/api/live/live-socket-messages.ts196
-rw-r--r--server/tests/api/live/live-views.ts130
-rw-r--r--server/tests/api/live/live.ts231
4 files changed, 334 insertions, 225 deletions
diff --git a/server/tests/api/live/index.ts b/server/tests/api/live/index.ts
index c733f564e..e6bcef49f 100644
--- a/server/tests/api/live/index.ts
+++ b/server/tests/api/live/index.ts
@@ -1,4 +1,6 @@
1import './live-constraints' 1import './live-constraints'
2import './live-socket-messages'
2import './live-permanent' 3import './live-permanent'
3import './live-save-replay' 4import './live-save-replay'
5import './live-views'
4import './live' 6import './live'
diff --git a/server/tests/api/live/live-socket-messages.ts b/server/tests/api/live/live-socket-messages.ts
new file mode 100644
index 000000000..e00909ade
--- /dev/null
+++ b/server/tests/api/live/live-socket-messages.ts
@@ -0,0 +1,196 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { getLiveNotificationSocket } from '@shared/extra-utils/socket/socket-io'
6import { VideoPrivacy, VideoState } from '@shared/models'
7import {
8 cleanupTests,
9 createLive,
10 doubleFollow,
11 flushAndRunMultipleServers,
12 getVideoIdFromUUID,
13 sendRTMPStreamInVideo,
14 ServerInfo,
15 setAccessTokensToServers,
16 setDefaultVideoChannel,
17 stopFfmpeg,
18 updateCustomSubConfig,
19 viewVideo,
20 wait,
21 waitJobs,
22 waitUntilLiveEnded,
23 waitUntilLivePublishedOnAllServers
24} from '../../../../shared/extra-utils'
25
26const expect = chai.expect
27
28describe('Test live', function () {
29 let servers: ServerInfo[] = []
30
31 before(async function () {
32 this.timeout(120000)
33
34 servers = await flushAndRunMultipleServers(2)
35
36 // Get the access tokens
37 await setAccessTokensToServers(servers)
38 await setDefaultVideoChannel(servers)
39
40 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
41 live: {
42 enabled: true,
43 allowReplay: true,
44 transcoding: {
45 enabled: false
46 }
47 }
48 })
49
50 // Server 1 and server 2 follow each other
51 await doubleFollow(servers[0], servers[1])
52 })
53
54 describe('Live socket messages', function () {
55
56 async function createLiveWrapper () {
57 const liveAttributes = {
58 name: 'live video',
59 channelId: servers[0].videoChannel.id,
60 privacy: VideoPrivacy.PUBLIC
61 }
62
63 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
64 return res.body.video.uuid
65 }
66
67 it('Should correctly send a message when the live starts and ends', async function () {
68 this.timeout(60000)
69
70 const localStateChanges: VideoState[] = []
71 const remoteStateChanges: VideoState[] = []
72
73 const liveVideoUUID = await createLiveWrapper()
74 await waitJobs(servers)
75
76 {
77 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
78
79 const localSocket = getLiveNotificationSocket(servers[0].url)
80 localSocket.on('state-change', data => localStateChanges.push(data.state))
81 localSocket.emit('subscribe', { videoId })
82 }
83
84 {
85 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
86
87 const remoteSocket = getLiveNotificationSocket(servers[1].url)
88 remoteSocket.on('state-change', data => remoteStateChanges.push(data.state))
89 remoteSocket.emit('subscribe', { videoId })
90 }
91
92 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
93
94 await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
95 await waitJobs(servers)
96
97 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
98 expect(stateChanges).to.have.length.at.least(1)
99 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED)
100 }
101
102 await stopFfmpeg(command)
103
104 for (const server of servers) {
105 await waitUntilLiveEnded(server.url, server.accessToken, liveVideoUUID)
106 }
107 await waitJobs(servers)
108
109 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
110 expect(stateChanges).to.have.length.at.least(2)
111 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.LIVE_ENDED)
112 }
113 })
114
115 it('Should correctly send views change notification', async function () {
116 this.timeout(60000)
117
118 let localLastVideoViews = 0
119 let remoteLastVideoViews = 0
120
121 const liveVideoUUID = await createLiveWrapper()
122 await waitJobs(servers)
123
124 {
125 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
126
127 const localSocket = getLiveNotificationSocket(servers[0].url)
128 localSocket.on('views-change', data => { localLastVideoViews = data.views })
129 localSocket.emit('subscribe', { videoId })
130 }
131
132 {
133 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
134
135 const remoteSocket = getLiveNotificationSocket(servers[1].url)
136 remoteSocket.on('views-change', data => { remoteLastVideoViews = data.views })
137 remoteSocket.emit('subscribe', { videoId })
138 }
139
140 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
141
142 await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
143 await waitJobs(servers)
144
145 expect(localLastVideoViews).to.equal(0)
146 expect(remoteLastVideoViews).to.equal(0)
147
148 await viewVideo(servers[0].url, liveVideoUUID)
149 await viewVideo(servers[1].url, liveVideoUUID)
150
151 await waitJobs(servers)
152 await wait(5000)
153 await waitJobs(servers)
154
155 expect(localLastVideoViews).to.equal(2)
156 expect(remoteLastVideoViews).to.equal(2)
157
158 await stopFfmpeg(command)
159 })
160
161 it('Should not receive a notification after unsubscribe', async function () {
162 this.timeout(120000)
163
164 const stateChanges: VideoState[] = []
165
166 const liveVideoUUID = await createLiveWrapper()
167 await waitJobs(servers)
168
169 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
170
171 const socket = getLiveNotificationSocket(servers[0].url)
172 socket.on('state-change', data => stateChanges.push(data.state))
173 socket.emit('subscribe', { videoId })
174
175 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
176
177 await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
178 await waitJobs(servers)
179
180 // Notifier waits before sending a notification
181 await wait(10000)
182
183 expect(stateChanges).to.have.lengthOf(1)
184 socket.emit('unsubscribe', { videoId })
185
186 await stopFfmpeg(command)
187 await waitJobs(servers)
188
189 expect(stateChanges).to.have.lengthOf(1)
190 })
191 })
192
193 after(async function () {
194 await cleanupTests(servers)
195 })
196})
diff --git a/server/tests/api/live/live-views.ts b/server/tests/api/live/live-views.ts
new file mode 100644
index 000000000..a44d21ffa
--- /dev/null
+++ b/server/tests/api/live/live-views.ts
@@ -0,0 +1,130 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { FfmpegCommand } from 'fluent-ffmpeg'
6import { VideoDetails, VideoPrivacy } from '@shared/models'
7import {
8 cleanupTests,
9 createLive,
10 doubleFollow,
11 flushAndRunMultipleServers,
12 getVideo,
13 sendRTMPStreamInVideo,
14 ServerInfo,
15 setAccessTokensToServers,
16 setDefaultVideoChannel,
17 stopFfmpeg,
18 updateCustomSubConfig,
19 viewVideo,
20 wait,
21 waitJobs,
22 waitUntilLivePublishedOnAllServers
23} from '../../../../shared/extra-utils'
24
25const expect = chai.expect
26
27describe('Test live', function () {
28 let servers: ServerInfo[] = []
29
30 before(async function () {
31 this.timeout(120000)
32
33 servers = await flushAndRunMultipleServers(2)
34
35 // Get the access tokens
36 await setAccessTokensToServers(servers)
37 await setDefaultVideoChannel(servers)
38
39 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
40 live: {
41 enabled: true,
42 allowReplay: true,
43 transcoding: {
44 enabled: false
45 }
46 }
47 })
48
49 // Server 1 and server 2 follow each other
50 await doubleFollow(servers[0], servers[1])
51 })
52
53 describe('Live views', function () {
54 let liveVideoId: string
55 let command: FfmpegCommand
56
57 async function countViews (expected: number) {
58 for (const server of servers) {
59 const res = await getVideo(server.url, liveVideoId)
60 const video: VideoDetails = res.body
61
62 expect(video.views).to.equal(expected)
63 }
64 }
65
66 before(async function () {
67 this.timeout(30000)
68
69 const liveAttributes = {
70 name: 'live video',
71 channelId: servers[0].videoChannel.id,
72 privacy: VideoPrivacy.PUBLIC
73 }
74
75 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
76 liveVideoId = res.body.video.uuid
77
78 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
79 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
80 await waitJobs(servers)
81 })
82
83 it('Should display no views for a live', async function () {
84 await countViews(0)
85 })
86
87 it('Should view a live twice and display 1 view', async function () {
88 this.timeout(30000)
89
90 await viewVideo(servers[0].url, liveVideoId)
91 await viewVideo(servers[0].url, liveVideoId)
92
93 await wait(7000)
94
95 await waitJobs(servers)
96
97 await countViews(1)
98 })
99
100 it('Should wait and display 0 views', async function () {
101 this.timeout(30000)
102
103 await wait(12000)
104 await waitJobs(servers)
105
106 await countViews(0)
107 })
108
109 it('Should view a live on a remote and on local and display 2 views', async function () {
110 this.timeout(30000)
111
112 await viewVideo(servers[0].url, liveVideoId)
113 await viewVideo(servers[1].url, liveVideoId)
114 await viewVideo(servers[1].url, liveVideoId)
115
116 await wait(7000)
117 await waitJobs(servers)
118
119 await countViews(2)
120 })
121
122 after(async function () {
123 await stopFfmpeg(command)
124 })
125 })
126
127 after(async function () {
128 await cleanupTests(servers)
129 })
130})
diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts
index 57fb58150..50397924e 100644
--- a/server/tests/api/live/live.ts
+++ b/server/tests/api/live/live.ts
@@ -2,10 +2,8 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { FfmpegCommand } from 'fluent-ffmpeg'
6import { join } from 'path' 5import { join } from 'path'
7import { ffprobePromise, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils' 6import { ffprobePromise, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils'
8import { getLiveNotificationSocket } from '@shared/extra-utils/socket/socket-io'
9import { LiveVideo, LiveVideoCreate, Video, VideoDetails, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models' 7import { LiveVideo, LiveVideoCreate, Video, VideoDetails, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models'
10import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 8import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
11import { 9import {
@@ -22,7 +20,6 @@ import {
22 getMyVideosWithFilter, 20 getMyVideosWithFilter,
23 getPlaylist, 21 getPlaylist,
24 getVideo, 22 getVideo,
25 getVideoIdFromUUID,
26 getVideosList, 23 getVideosList,
27 getVideosWithFilters, 24 getVideosWithFilters,
28 killallServers, 25 killallServers,
@@ -40,11 +37,11 @@ import {
40 updateCustomSubConfig, 37 updateCustomSubConfig,
41 updateLive, 38 updateLive,
42 uploadVideoAndGetId, 39 uploadVideoAndGetId,
43 viewVideo,
44 wait, 40 wait,
45 waitJobs, 41 waitJobs,
46 waitUntilLiveEnded, 42 waitUntilLiveEnded,
47 waitUntilLivePublished, 43 waitUntilLivePublished,
44 waitUntilLivePublishedOnAllServers,
48 waitUntilLiveSegmentGeneration 45 waitUntilLiveSegmentGeneration
49} from '../../../../shared/extra-utils' 46} from '../../../../shared/extra-utils'
50 47
@@ -53,12 +50,6 @@ const expect = chai.expect
53describe('Test live', function () { 50describe('Test live', function () {
54 let servers: ServerInfo[] = [] 51 let servers: ServerInfo[] = []
55 52
56 async function waitUntilLivePublishedOnAllServers (videoId: string) {
57 for (const server of servers) {
58 await waitUntilLivePublished(server.url, server.accessToken, videoId)
59 }
60 }
61
62 before(async function () { 53 before(async function () {
63 this.timeout(120000) 54 this.timeout(120000)
64 55
@@ -247,7 +238,7 @@ describe('Test live', function () {
247 liveVideoId = resLive.body.video.uuid 238 liveVideoId = resLive.body.video.uuid
248 239
249 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) 240 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
250 await waitUntilLivePublishedOnAllServers(liveVideoId) 241 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
251 await waitJobs(servers) 242 await waitJobs(servers)
252 }) 243 })
253 244
@@ -461,7 +452,7 @@ describe('Test live', function () {
461 liveVideoId = await createLiveWrapper(false) 452 liveVideoId = await createLiveWrapper(false)
462 453
463 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) 454 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
464 await waitUntilLivePublishedOnAllServers(liveVideoId) 455 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
465 await waitJobs(servers) 456 await waitJobs(servers)
466 457
467 await testVideoResolutions(liveVideoId, [ 720 ]) 458 await testVideoResolutions(liveVideoId, [ 720 ])
@@ -477,7 +468,7 @@ describe('Test live', function () {
477 liveVideoId = await createLiveWrapper(false) 468 liveVideoId = await createLiveWrapper(false)
478 469
479 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) 470 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
480 await waitUntilLivePublishedOnAllServers(liveVideoId) 471 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
481 await waitJobs(servers) 472 await waitJobs(servers)
482 473
483 await testVideoResolutions(liveVideoId, resolutions) 474 await testVideoResolutions(liveVideoId, resolutions)
@@ -494,7 +485,7 @@ describe('Test live', function () {
494 liveVideoId = await createLiveWrapper(true) 485 liveVideoId = await createLiveWrapper(true)
495 486
496 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId, 'video_short2.webm') 487 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId, 'video_short2.webm')
497 await waitUntilLivePublishedOnAllServers(liveVideoId) 488 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
498 await waitJobs(servers) 489 await waitJobs(servers)
499 490
500 await testVideoResolutions(liveVideoId, resolutions) 491 await testVideoResolutions(liveVideoId, resolutions)
@@ -504,7 +495,7 @@ describe('Test live', function () {
504 495
505 await waitJobs(servers) 496 await waitJobs(servers)
506 497
507 await waitUntilLivePublishedOnAllServers(liveVideoId) 498 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
508 499
509 const bitrateLimits = { 500 const bitrateLimits = {
510 720: 5000 * 1000, // 60FPS 501 720: 5000 * 1000, // 60FPS
@@ -559,216 +550,6 @@ describe('Test live', function () {
559 }) 550 })
560 }) 551 })
561 552
562 describe('Live views', function () {
563 let liveVideoId: string
564 let command: FfmpegCommand
565
566 async function countViews (expected: number) {
567 for (const server of servers) {
568 const res = await getVideo(server.url, liveVideoId)
569 const video: VideoDetails = res.body
570
571 expect(video.views).to.equal(expected)
572 }
573 }
574
575 before(async function () {
576 this.timeout(30000)
577
578 const liveAttributes = {
579 name: 'live video',
580 channelId: servers[0].videoChannel.id,
581 privacy: VideoPrivacy.PUBLIC
582 }
583
584 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
585 liveVideoId = res.body.video.uuid
586
587 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
588 await waitUntilLivePublishedOnAllServers(liveVideoId)
589 await waitJobs(servers)
590 })
591
592 it('Should display no views for a live', async function () {
593 await countViews(0)
594 })
595
596 it('Should view a live twice and display 1 view', async function () {
597 this.timeout(30000)
598
599 await viewVideo(servers[0].url, liveVideoId)
600 await viewVideo(servers[0].url, liveVideoId)
601
602 await wait(7000)
603
604 await waitJobs(servers)
605
606 await countViews(1)
607 })
608
609 it('Should wait and display 0 views', async function () {
610 this.timeout(30000)
611
612 await wait(7000)
613 await waitJobs(servers)
614
615 await countViews(0)
616 })
617
618 it('Should view a live on a remote and on local and display 2 views', async function () {
619 this.timeout(30000)
620
621 await viewVideo(servers[0].url, liveVideoId)
622 await viewVideo(servers[1].url, liveVideoId)
623 await viewVideo(servers[1].url, liveVideoId)
624
625 await wait(7000)
626 await waitJobs(servers)
627
628 await countViews(2)
629 })
630
631 after(async function () {
632 await stopFfmpeg(command)
633 })
634 })
635
636 describe('Live socket messages', function () {
637
638 async function createLiveWrapper () {
639 const liveAttributes = {
640 name: 'live video',
641 channelId: servers[0].videoChannel.id,
642 privacy: VideoPrivacy.PUBLIC
643 }
644
645 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
646 return res.body.video.uuid
647 }
648
649 it('Should correctly send a message when the live starts and ends', async function () {
650 this.timeout(60000)
651
652 const localStateChanges: VideoState[] = []
653 const remoteStateChanges: VideoState[] = []
654
655 const liveVideoUUID = await createLiveWrapper()
656 await waitJobs(servers)
657
658 {
659 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
660
661 const localSocket = getLiveNotificationSocket(servers[0].url)
662 localSocket.on('state-change', data => localStateChanges.push(data.state))
663 localSocket.emit('subscribe', { videoId })
664 }
665
666 {
667 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
668
669 const remoteSocket = getLiveNotificationSocket(servers[1].url)
670 remoteSocket.on('state-change', data => remoteStateChanges.push(data.state))
671 remoteSocket.emit('subscribe', { videoId })
672 }
673
674 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
675
676 await waitUntilLivePublishedOnAllServers(liveVideoUUID)
677 await waitJobs(servers)
678
679 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
680 expect(stateChanges).to.have.length.at.least(1)
681 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED)
682 }
683
684 await stopFfmpeg(command)
685
686 for (const server of servers) {
687 await waitUntilLiveEnded(server.url, server.accessToken, liveVideoUUID)
688 }
689 await waitJobs(servers)
690
691 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
692 expect(stateChanges).to.have.length.at.least(2)
693 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.LIVE_ENDED)
694 }
695 })
696
697 it('Should correctly send views change notification', async function () {
698 this.timeout(60000)
699
700 let localLastVideoViews = 0
701 let remoteLastVideoViews = 0
702
703 const liveVideoUUID = await createLiveWrapper()
704 await waitJobs(servers)
705
706 {
707 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
708
709 const localSocket = getLiveNotificationSocket(servers[0].url)
710 localSocket.on('views-change', data => { localLastVideoViews = data.views })
711 localSocket.emit('subscribe', { videoId })
712 }
713
714 {
715 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
716
717 const remoteSocket = getLiveNotificationSocket(servers[1].url)
718 remoteSocket.on('views-change', data => { remoteLastVideoViews = data.views })
719 remoteSocket.emit('subscribe', { videoId })
720 }
721
722 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
723
724 await waitUntilLivePublishedOnAllServers(liveVideoUUID)
725 await waitJobs(servers)
726
727 expect(localLastVideoViews).to.equal(0)
728 expect(remoteLastVideoViews).to.equal(0)
729
730 await viewVideo(servers[0].url, liveVideoUUID)
731 await viewVideo(servers[1].url, liveVideoUUID)
732
733 await waitJobs(servers)
734 await wait(5000)
735 await waitJobs(servers)
736
737 expect(localLastVideoViews).to.equal(2)
738 expect(remoteLastVideoViews).to.equal(2)
739
740 await stopFfmpeg(command)
741 })
742
743 it('Should not receive a notification after unsubscribe', async function () {
744 this.timeout(60000)
745
746 const stateChanges: VideoState[] = []
747
748 const liveVideoUUID = await createLiveWrapper()
749 await waitJobs(servers)
750
751 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
752
753 const socket = getLiveNotificationSocket(servers[0].url)
754 socket.on('state-change', data => stateChanges.push(data.state))
755 socket.emit('subscribe', { videoId })
756
757 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
758
759 await waitUntilLivePublishedOnAllServers(liveVideoUUID)
760 await waitJobs(servers)
761
762 expect(stateChanges).to.have.lengthOf(1)
763 socket.emit('unsubscribe', { videoId })
764
765 await stopFfmpeg(command)
766 await waitJobs(servers)
767
768 expect(stateChanges).to.have.lengthOf(1)
769 })
770 })
771
772 describe('After a server restart', function () { 553 describe('After a server restart', function () {
773 let liveVideoId: string 554 let liveVideoId: string
774 let liveVideoReplayId: string 555 let liveVideoReplayId: string