diff options
Diffstat (limited to 'server/tests/api/transcoding')
-rw-r--r-- | server/tests/api/transcoding/create-transcoding.ts | 10 | ||||
-rw-r--r-- | server/tests/api/transcoding/hls.ts | 163 | ||||
-rw-r--r-- | server/tests/api/transcoding/index.ts | 1 | ||||
-rw-r--r-- | server/tests/api/transcoding/update-while-transcoding.ts | 151 |
4 files changed, 181 insertions, 144 deletions
diff --git a/server/tests/api/transcoding/create-transcoding.ts b/server/tests/api/transcoding/create-transcoding.ts index a50bf7654..372f5332a 100644 --- a/server/tests/api/transcoding/create-transcoding.ts +++ b/server/tests/api/transcoding/create-transcoding.ts | |||
@@ -20,7 +20,7 @@ import { | |||
20 | async function checkFilesInObjectStorage (video: VideoDetails) { | 20 | async function checkFilesInObjectStorage (video: VideoDetails) { |
21 | for (const file of video.files) { | 21 | for (const file of video.files) { |
22 | expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 22 | expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) |
23 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 23 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
24 | } | 24 | } |
25 | 25 | ||
26 | if (video.streamingPlaylists.length === 0) return | 26 | if (video.streamingPlaylists.length === 0) return |
@@ -28,14 +28,14 @@ async function checkFilesInObjectStorage (video: VideoDetails) { | |||
28 | const hlsPlaylist = video.streamingPlaylists[0] | 28 | const hlsPlaylist = video.streamingPlaylists[0] |
29 | for (const file of hlsPlaylist.files) { | 29 | for (const file of hlsPlaylist.files) { |
30 | expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 30 | expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) |
31 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 31 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
32 | } | 32 | } |
33 | 33 | ||
34 | expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 34 | expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getPlaylistBaseUrl()) |
35 | await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) | 35 | await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
36 | 36 | ||
37 | expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getPlaylistBaseUrl()) | 37 | expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getPlaylistBaseUrl()) |
38 | await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) | 38 | await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) |
39 | } | 39 | } |
40 | 40 | ||
41 | function runTests (objectStorage: boolean) { | 41 | function runTests (objectStorage: boolean) { |
@@ -234,7 +234,7 @@ function runTests (objectStorage: boolean) { | |||
234 | 234 | ||
235 | it('Should have correctly deleted previous files', async function () { | 235 | it('Should have correctly deleted previous files', async function () { |
236 | for (const fileUrl of shouldBeDeleted) { | 236 | for (const fileUrl of shouldBeDeleted) { |
237 | await makeRawRequest(fileUrl, HttpStatusCode.NOT_FOUND_404) | 237 | await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
238 | } | 238 | } |
239 | }) | 239 | }) |
240 | 240 | ||
diff --git a/server/tests/api/transcoding/hls.ts b/server/tests/api/transcoding/hls.ts index 252422e5d..7b5492cd4 100644 --- a/server/tests/api/transcoding/hls.ts +++ b/server/tests/api/transcoding/hls.ts | |||
@@ -1,168 +1,48 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { join } from 'path' |
4 | import { basename, join } from 'path' | 4 | import { checkDirectoryIsEmpty, checkTmpIsEmpty, completeCheckHlsPlaylist } from '@server/tests/shared' |
5 | import { | 5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' |
6 | checkDirectoryIsEmpty, | 6 | import { HttpStatusCode } from '@shared/models' |
7 | checkResolutionsInMasterPlaylist, | ||
8 | checkSegmentHash, | ||
9 | checkTmpIsEmpty, | ||
10 | expectStartWith, | ||
11 | hlsInfohashExist | ||
12 | } from '@server/tests/shared' | ||
13 | import { areObjectStorageTestsDisabled, removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' | ||
14 | import { HttpStatusCode, VideoStreamingPlaylistType } from '@shared/models' | ||
15 | import { | 7 | import { |
16 | cleanupTests, | 8 | cleanupTests, |
17 | createMultipleServers, | 9 | createMultipleServers, |
18 | doubleFollow, | 10 | doubleFollow, |
19 | makeRawRequest, | ||
20 | ObjectStorageCommand, | 11 | ObjectStorageCommand, |
21 | PeerTubeServer, | 12 | PeerTubeServer, |
22 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
23 | waitJobs, | 14 | waitJobs |
24 | webtorrentAdd | ||
25 | } from '@shared/server-commands' | 15 | } from '@shared/server-commands' |
26 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | 16 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' |
27 | 17 | ||
28 | async function checkHlsPlaylist (options: { | ||
29 | servers: PeerTubeServer[] | ||
30 | videoUUID: string | ||
31 | hlsOnly: boolean | ||
32 | |||
33 | resolutions?: number[] | ||
34 | objectStorageBaseUrl: string | ||
35 | }) { | ||
36 | const { videoUUID, hlsOnly, objectStorageBaseUrl } = options | ||
37 | |||
38 | const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] | ||
39 | |||
40 | for (const server of options.servers) { | ||
41 | const videoDetails = await server.videos.get({ id: videoUUID }) | ||
42 | const baseUrl = `http://${videoDetails.account.host}` | ||
43 | |||
44 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) | ||
45 | |||
46 | const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) | ||
47 | expect(hlsPlaylist).to.not.be.undefined | ||
48 | |||
49 | const hlsFiles = hlsPlaylist.files | ||
50 | expect(hlsFiles).to.have.lengthOf(resolutions.length) | ||
51 | |||
52 | if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) | ||
53 | else expect(videoDetails.files).to.have.lengthOf(resolutions.length) | ||
54 | |||
55 | // Check JSON files | ||
56 | for (const resolution of resolutions) { | ||
57 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
58 | expect(file).to.not.be.undefined | ||
59 | |||
60 | expect(file.magnetUri).to.have.lengthOf.above(2) | ||
61 | expect(file.torrentUrl).to.match( | ||
62 | new RegExp(`http://${server.host}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`) | ||
63 | ) | ||
64 | |||
65 | if (objectStorageBaseUrl) { | ||
66 | expectStartWith(file.fileUrl, objectStorageBaseUrl) | ||
67 | } else { | ||
68 | expect(file.fileUrl).to.match( | ||
69 | new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`) | ||
70 | ) | ||
71 | } | ||
72 | |||
73 | expect(file.resolution.label).to.equal(resolution + 'p') | ||
74 | |||
75 | await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) | ||
76 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | ||
77 | |||
78 | const torrent = await webtorrentAdd(file.magnetUri, true) | ||
79 | expect(torrent.files).to.be.an('array') | ||
80 | expect(torrent.files.length).to.equal(1) | ||
81 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | ||
82 | } | ||
83 | |||
84 | // Check master playlist | ||
85 | { | ||
86 | await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) | ||
87 | |||
88 | const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl }) | ||
89 | |||
90 | let i = 0 | ||
91 | for (const resolution of resolutions) { | ||
92 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | ||
93 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | ||
94 | |||
95 | const url = 'http://' + videoDetails.account.host | ||
96 | await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i) | ||
97 | |||
98 | i++ | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // Check resolution playlists | ||
103 | { | ||
104 | for (const resolution of resolutions) { | ||
105 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
106 | const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' | ||
107 | |||
108 | const url = objectStorageBaseUrl | ||
109 | ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` | ||
110 | : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}` | ||
111 | |||
112 | const subPlaylist = await server.streamingPlaylists.get({ url }) | ||
113 | |||
114 | expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) | ||
115 | expect(subPlaylist).to.contain(basename(file.fileUrl)) | ||
116 | } | ||
117 | } | ||
118 | |||
119 | { | ||
120 | const baseUrlAndPath = objectStorageBaseUrl | ||
121 | ? objectStorageBaseUrl + 'hls/' + videoUUID | ||
122 | : baseUrl + '/static/streaming-playlists/hls/' + videoUUID | ||
123 | |||
124 | for (const resolution of resolutions) { | ||
125 | await checkSegmentHash({ | ||
126 | server, | ||
127 | baseUrlPlaylist: baseUrlAndPath, | ||
128 | baseUrlSegment: baseUrlAndPath, | ||
129 | resolution, | ||
130 | hlsPlaylist | ||
131 | }) | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | describe('Test HLS videos', function () { | 18 | describe('Test HLS videos', function () { |
138 | let servers: PeerTubeServer[] = [] | 19 | let servers: PeerTubeServer[] = [] |
139 | let videoUUID = '' | ||
140 | let videoAudioUUID = '' | ||
141 | 20 | ||
142 | function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { | 21 | function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { |
22 | const videoUUIDs: string[] = [] | ||
143 | 23 | ||
144 | it('Should upload a video and transcode it to HLS', async function () { | 24 | it('Should upload a video and transcode it to HLS', async function () { |
145 | this.timeout(120000) | 25 | this.timeout(120000) |
146 | 26 | ||
147 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) | 27 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) |
148 | videoUUID = uuid | 28 | videoUUIDs.push(uuid) |
149 | 29 | ||
150 | await waitJobs(servers) | 30 | await waitJobs(servers) |
151 | 31 | ||
152 | await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) | 32 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) |
153 | }) | 33 | }) |
154 | 34 | ||
155 | it('Should upload an audio file and transcode it to HLS', async function () { | 35 | it('Should upload an audio file and transcode it to HLS', async function () { |
156 | this.timeout(120000) | 36 | this.timeout(120000) |
157 | 37 | ||
158 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) | 38 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) |
159 | videoAudioUUID = uuid | 39 | videoUUIDs.push(uuid) |
160 | 40 | ||
161 | await waitJobs(servers) | 41 | await waitJobs(servers) |
162 | 42 | ||
163 | await checkHlsPlaylist({ | 43 | await completeCheckHlsPlaylist({ |
164 | servers, | 44 | servers, |
165 | videoUUID: videoAudioUUID, | 45 | videoUUID: uuid, |
166 | hlsOnly, | 46 | hlsOnly, |
167 | resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], | 47 | resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], |
168 | objectStorageBaseUrl | 48 | objectStorageBaseUrl |
@@ -172,31 +52,36 @@ describe('Test HLS videos', function () { | |||
172 | it('Should update the video', async function () { | 52 | it('Should update the video', async function () { |
173 | this.timeout(30000) | 53 | this.timeout(30000) |
174 | 54 | ||
175 | await servers[0].videos.update({ id: videoUUID, attributes: { name: 'video 1 updated' } }) | 55 | await servers[0].videos.update({ id: videoUUIDs[0], attributes: { name: 'video 1 updated' } }) |
176 | 56 | ||
177 | await waitJobs(servers) | 57 | await waitJobs(servers) |
178 | 58 | ||
179 | await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) | 59 | await completeCheckHlsPlaylist({ servers, videoUUID: videoUUIDs[0], hlsOnly, objectStorageBaseUrl }) |
180 | }) | 60 | }) |
181 | 61 | ||
182 | it('Should delete videos', async function () { | 62 | it('Should delete videos', async function () { |
183 | this.timeout(10000) | 63 | this.timeout(10000) |
184 | 64 | ||
185 | await servers[0].videos.remove({ id: videoUUID }) | 65 | for (const uuid of videoUUIDs) { |
186 | await servers[0].videos.remove({ id: videoAudioUUID }) | 66 | await servers[0].videos.remove({ id: uuid }) |
67 | } | ||
187 | 68 | ||
188 | await waitJobs(servers) | 69 | await waitJobs(servers) |
189 | 70 | ||
190 | for (const server of servers) { | 71 | for (const server of servers) { |
191 | await server.videos.get({ id: videoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 72 | for (const uuid of videoUUIDs) { |
192 | await server.videos.get({ id: videoAudioUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 73 | await server.videos.get({ id: uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
74 | } | ||
193 | } | 75 | } |
194 | }) | 76 | }) |
195 | 77 | ||
196 | it('Should have the playlists/segment deleted from the disk', async function () { | 78 | it('Should have the playlists/segment deleted from the disk', async function () { |
197 | for (const server of servers) { | 79 | for (const server of servers) { |
198 | await checkDirectoryIsEmpty(server, 'videos') | 80 | await checkDirectoryIsEmpty(server, 'videos', [ 'private' ]) |
199 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls')) | 81 | await checkDirectoryIsEmpty(server, join('videos', 'private')) |
82 | |||
83 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls'), [ 'private' ]) | ||
84 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls', 'private')) | ||
200 | } | 85 | } |
201 | }) | 86 | }) |
202 | 87 | ||
diff --git a/server/tests/api/transcoding/index.ts b/server/tests/api/transcoding/index.ts index 0cc28b4a4..9866418d6 100644 --- a/server/tests/api/transcoding/index.ts +++ b/server/tests/api/transcoding/index.ts | |||
@@ -2,4 +2,5 @@ export * from './audio-only' | |||
2 | export * from './create-transcoding' | 2 | export * from './create-transcoding' |
3 | export * from './hls' | 3 | export * from './hls' |
4 | export * from './transcoder' | 4 | export * from './transcoder' |
5 | export * from './update-while-transcoding' | ||
5 | export * from './video-studio' | 6 | export * from './video-studio' |
diff --git a/server/tests/api/transcoding/update-while-transcoding.ts b/server/tests/api/transcoding/update-while-transcoding.ts new file mode 100644 index 000000000..5ca923392 --- /dev/null +++ b/server/tests/api/transcoding/update-while-transcoding.ts | |||
@@ -0,0 +1,151 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { completeCheckHlsPlaylist } from '@server/tests/shared' | ||
4 | import { areObjectStorageTestsDisabled, wait } from '@shared/core-utils' | ||
5 | import { VideoPrivacy } from '@shared/models' | ||
6 | import { | ||
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | ObjectStorageCommand, | ||
11 | PeerTubeServer, | ||
12 | setAccessTokensToServers, | ||
13 | waitJobs | ||
14 | } from '@shared/server-commands' | ||
15 | |||
16 | describe('Test update video privacy while transcoding', function () { | ||
17 | let servers: PeerTubeServer[] = [] | ||
18 | |||
19 | const videoUUIDs: string[] = [] | ||
20 | |||
21 | function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { | ||
22 | |||
23 | it('Should not have an error while quickly updating a private video to public after upload #1', async function () { | ||
24 | this.timeout(360_000) | ||
25 | |||
26 | const attributes = { | ||
27 | name: 'quick update', | ||
28 | privacy: VideoPrivacy.PRIVATE | ||
29 | } | ||
30 | |||
31 | const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: false }) | ||
32 | await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
33 | videoUUIDs.push(uuid) | ||
34 | |||
35 | await waitJobs(servers) | ||
36 | |||
37 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) | ||
38 | }) | ||
39 | |||
40 | it('Should not have an error while quickly updating a private video to public after upload #2', async function () { | ||
41 | |||
42 | { | ||
43 | const attributes = { | ||
44 | name: 'quick update 2', | ||
45 | privacy: VideoPrivacy.PRIVATE | ||
46 | } | ||
47 | |||
48 | const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) | ||
49 | await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
50 | videoUUIDs.push(uuid) | ||
51 | |||
52 | await waitJobs(servers) | ||
53 | |||
54 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) | ||
55 | } | ||
56 | }) | ||
57 | |||
58 | it('Should not have an error while quickly updating a private video to public after upload #3', async function () { | ||
59 | const attributes = { | ||
60 | name: 'quick update 3', | ||
61 | privacy: VideoPrivacy.PRIVATE | ||
62 | } | ||
63 | |||
64 | const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) | ||
65 | await wait(1000) | ||
66 | await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
67 | videoUUIDs.push(uuid) | ||
68 | |||
69 | await waitJobs(servers) | ||
70 | |||
71 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) | ||
72 | }) | ||
73 | } | ||
74 | |||
75 | before(async function () { | ||
76 | this.timeout(120000) | ||
77 | |||
78 | const configOverride = { | ||
79 | transcoding: { | ||
80 | enabled: true, | ||
81 | allow_audio_files: true, | ||
82 | hls: { | ||
83 | enabled: true | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | servers = await createMultipleServers(2, configOverride) | ||
88 | |||
89 | // Get the access tokens | ||
90 | await setAccessTokensToServers(servers) | ||
91 | |||
92 | // Server 1 and server 2 follow each other | ||
93 | await doubleFollow(servers[0], servers[1]) | ||
94 | }) | ||
95 | |||
96 | describe('With WebTorrent & HLS enabled', function () { | ||
97 | runTestSuite(false) | ||
98 | }) | ||
99 | |||
100 | describe('With only HLS enabled', function () { | ||
101 | |||
102 | before(async function () { | ||
103 | await servers[0].config.updateCustomSubConfig({ | ||
104 | newConfig: { | ||
105 | transcoding: { | ||
106 | enabled: true, | ||
107 | allowAudioFiles: true, | ||
108 | resolutions: { | ||
109 | '144p': false, | ||
110 | '240p': true, | ||
111 | '360p': true, | ||
112 | '480p': true, | ||
113 | '720p': true, | ||
114 | '1080p': true, | ||
115 | '1440p': true, | ||
116 | '2160p': true | ||
117 | }, | ||
118 | hls: { | ||
119 | enabled: true | ||
120 | }, | ||
121 | webtorrent: { | ||
122 | enabled: false | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | }) | ||
127 | }) | ||
128 | |||
129 | runTestSuite(true) | ||
130 | }) | ||
131 | |||
132 | describe('With object storage enabled', function () { | ||
133 | if (areObjectStorageTestsDisabled()) return | ||
134 | |||
135 | before(async function () { | ||
136 | this.timeout(120000) | ||
137 | |||
138 | const configOverride = ObjectStorageCommand.getDefaultConfig() | ||
139 | await ObjectStorageCommand.prepareDefaultBuckets() | ||
140 | |||
141 | await servers[0].kill() | ||
142 | await servers[0].run(configOverride) | ||
143 | }) | ||
144 | |||
145 | runTestSuite(true, ObjectStorageCommand.getPlaylistBaseUrl()) | ||
146 | }) | ||
147 | |||
148 | after(async function () { | ||
149 | await cleanupTests(servers) | ||
150 | }) | ||
151 | }) | ||